diff options
-rw-r--r-- | apps/user_ldap/group_ldap.php | 4 | ||||
-rw-r--r-- | apps/user_ldap/lib/access.php | 27 | ||||
-rwxr-xr-x | apps/user_ldap/tests/.htaccess | 14 | ||||
-rw-r--r-- | apps/user_ldap/tests/group_ldap.php | 4 | ||||
-rw-r--r-- | apps/user_ldap/tests/integration/lib/IntegrationTestAccessGroupsMatchFilter.php | 158 | ||||
-rw-r--r-- | apps/user_ldap/tests/integration/readme.md | 60 | ||||
-rwxr-xr-x | apps/user_ldap/tests/integration/run-test.sh | 17 | ||||
-rw-r--r-- | apps/user_ldap/tests/integration/setup-scripts/createExplicitGroups.php | 52 | ||||
-rw-r--r-- | apps/user_ldap/tests/integration/setup-scripts/createExplicitUsers.php | 54 | ||||
-rw-r--r-- | lib/base.php | 10 | ||||
-rw-r--r-- | lib/private/app.php | 5 | ||||
-rw-r--r-- | lib/private/cache/file.php | 13 | ||||
-rw-r--r-- | lib/private/files/view.php | 5 | ||||
-rw-r--r-- | lib/private/share/share.php | 22 | ||||
-rw-r--r-- | tests/lib/app.php | 10 | ||||
-rw-r--r-- | tests/lib/cache/file.php | 94 | ||||
-rw-r--r-- | version.php | 4 |
17 files changed, 532 insertions, 21 deletions
diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php index 0395a4a80e3..a7a90c75832 100644 --- a/apps/user_ldap/group_ldap.php +++ b/apps/user_ldap/group_ldap.php @@ -378,9 +378,11 @@ class GROUP_LDAP extends BackendUtility implements \OCP\GroupInterface { && intval($this->access->connection->useMemberOfToDetectMembership) === 1 ) { $groupDNs = $this->access->readAttribute($userDN, 'memberOf'); + if (is_array($groupDNs)) { + $groupDNs = $this->access->groupsMatchFilter($groupDNs); foreach ($groupDNs as $dn) { - $groups[] = $this->access->dn2groupname($dn);; + $groups[] = $this->access->dn2groupname($dn); } } if($primaryGroup !== false) { diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index f38d11d4be3..b201220d725 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -347,6 +347,33 @@ class Access extends LDAPUtility implements user\IUserTools { } /** + * accepts an array of group DNs and tests whether they match the user + * filter by doing read operations against the group entries. Returns an + * array of DNs that match the filter. + * + * @param string[] $groupDNs + * @return string[] + */ + public function groupsMatchFilter($groupDNs) { + $validGroupDNs = []; + foreach($groupDNs as $dn) { + $cacheKey = 'groupsMatchFilter-'.$dn; + if($this->connection->isCached($cacheKey)) { + if($this->connection->getFromCache($cacheKey)) { + $validGroupDNs[] = $dn; + } + continue; + } + + $result = $this->readAttribute($dn, 'cn', $this->connection->ldapGroupFilter); + if(is_array($result)) { + $validGroupDNs[] = $dn; + } + } + return $validGroupDNs; + } + + /** * returns the internal ownCloud name for the given LDAP DN of the user, false on DN outside of search DN or failure * @param string $dn the dn of the user object * @param string $ldapName optional, the display name of the object diff --git a/apps/user_ldap/tests/.htaccess b/apps/user_ldap/tests/.htaccess new file mode 100755 index 00000000000..5e068d28661 --- /dev/null +++ b/apps/user_ldap/tests/.htaccess @@ -0,0 +1,14 @@ +# Generated by ownCloud on 2015-06-18 14:16:40 +# line below if for Apache 2.4 +<ifModule mod_authz_core.c> +Require all denied +</ifModule> + +# line below if for Apache 2.2 +<ifModule !mod_authz_core.c> +deny from all +Satisfy All +</ifModule> + +# section for Apache 2.2 and 2.4 +IndexIgnore * diff --git a/apps/user_ldap/tests/group_ldap.php b/apps/user_ldap/tests/group_ldap.php index aeb306174f0..f716618ce48 100644 --- a/apps/user_ldap/tests/group_ldap.php +++ b/apps/user_ldap/tests/group_ldap.php @@ -404,6 +404,10 @@ class Test_Group_Ldap extends \Test\TestCase { ->method('dn2groupname') ->will($this->returnArgument(0)); + $access->expects($this->once()) + ->method('groupsMatchFilter') + ->will($this->returnArgument(0)); + $groupBackend = new GroupLDAP($access); $groups = $groupBackend->getUserGroups('userX'); diff --git a/apps/user_ldap/tests/integration/lib/IntegrationTestAccessGroupsMatchFilter.php b/apps/user_ldap/tests/integration/lib/IntegrationTestAccessGroupsMatchFilter.php new file mode 100644 index 00000000000..6560153bb63 --- /dev/null +++ b/apps/user_ldap/tests/integration/lib/IntegrationTestAccessGroupsMatchFilter.php @@ -0,0 +1,158 @@ +<?php +/** + * Created by PhpStorm. + * User: blizzz + * Date: 26.06.15 + * Time: 18:13 + */ + +use OCA\user_ldap\lib\LDAP; + +require_once __DIR__ . '/../../../../../lib/base.php'; + +class IntegrationTestAccessGroupsMatchFilter { + /** @var LDAP */ + protected $ldap; + + /** @var \OCA\user_ldap\lib\Connection */ + protected $connection; + + /** @var \OCA\user_ldap\lib\Access */ + protected $access; + + /** @var string */ + protected $base; + + /** @var string[] */ + protected $server; + + public function __construct($host, $port, $bind, $pwd, $base) { + $this->base = $base; + $this->server = [ + 'host' => $host, + 'port' => $port, + 'dn' => $bind, + 'pwd' => $pwd + ]; + } + + /** + * prepares the LDAP environement and sets up a test configuration for + * the LDAP backend. + */ + public function init() { + require('setup-scripts/createExplicitUsers.php'); + require('setup-scripts/createExplicitGroups.php'); + + $this->initLDAPWrapper(); + $this->initConnection(); + $this->initAccess(); + } + + /** + * runs the test cases while outputting progress and result information + * + * If a test failed, the script is exited with return code 1. + */ + public function run() { + $cases = ['case1', 'case2']; + + foreach ($cases as $case) { + print("running $case " . PHP_EOL); + if (!$this->$case()) { + print(PHP_EOL . '>>> !!! Test ' . $case . ' FAILED !!! <<<' . PHP_EOL . PHP_EOL); + exit(1); + } + } + + print('Tests succeeded' . PHP_EOL); + } + + /** + * tests whether the group filter works with one specific group, while the + * input is the same. + * + * @return bool + */ + private function case1() { + $this->connection->setConfiguration(['ldapGroupFilter' => 'cn=RedGroup']); + + $dns = ['cn=RedGroup,ou=Groups,' . $this->base]; + $result = $this->access->groupsMatchFilter($dns); + return ($dns === $result); + } + + /** + * Tests whether a filter for limited groups is effective when more existing + * groups were passed for validation. + * + * @return bool + */ + private function case2() { + $this->connection->setConfiguration(['ldapGroupFilter' => '(|(cn=RedGroup)(cn=PurpleGroup))']); + + $dns = [ + 'cn=RedGroup,ou=Groups,' . $this->base, + 'cn=BlueGroup,ou=Groups,' . $this->base, + 'cn=PurpleGroup,ou=Groups,' . $this->base + ]; + $result = $this->access->groupsMatchFilter($dns); + + $status = + count($result) === 2 + && in_array('cn=RedGroup,ou=Groups,' . $this->base, $result) + && in_array('cn=PurpleGroup,ou=Groups,' . $this->base, $result); + + return $status; + } + + /** + * initializes the Access test instance + */ + private function initAccess() { + $this->access = new \OCA\user_ldap\lib\Access($this->connection, $this->ldap, new FakeManager()); + } + + /** + * initializes the test LDAP wrapper + */ + private function initLDAPWrapper() { + $this->ldap = new LDAP(); + } + + /** + * sets up the LDAP configuration to be used for the test + */ + private function initConnection() { + $this->connection = new \OCA\user_ldap\lib\Connection($this->ldap, '', null); + $this->connection->setConfiguration([ + 'ldapHost' => $this->server['host'], + 'ldapPort' => $this->server['port'], + 'ldapBase' => $this->base, + 'ldapAgentName' => $this->server['dn'], + 'ldapAgentPassword' => $this->server['pwd'], + 'ldapUserFilter' => 'objectclass=inetOrgPerson', + 'ldapUserDisplayName' => 'displayName', + 'ldapGroupDisplayName' => 'cn', + 'ldapLoginFilter' => 'uid=%uid', + 'ldapCacheTTL' => 0, + 'ldapConfigurationActive' => 1, + ]); + } +} + +/** + * Class FakeManager + * + * this is a mock of \OCA\user_ldap\lib\user\Manager which is a dependency of + * Access, that pulls plenty more things in. Because it is not needed in the + * scope of these tests, we replace it with a mock. + */ +class FakeManager extends \OCA\user_ldap\lib\user\Manager { + public function __construct() {} +} + +require_once('setup-scripts/config.php'); +$test = new IntegrationTestAccessGroupsMatchFilter($host, $port, $adn, $apwd, $bdn); +$test->init(); +$test->run(); diff --git a/apps/user_ldap/tests/integration/readme.md b/apps/user_ldap/tests/integration/readme.md new file mode 100644 index 00000000000..e20efef8fdc --- /dev/null +++ b/apps/user_ldap/tests/integration/readme.md @@ -0,0 +1,60 @@ +# Requirements # + +Have (as in do copy if not already done) the following files from https://github.com/owncloud/administration/tree/master/ldap-testing copied into the directory "setup-scripts": + + * start.sh + * stop.sh + * config.php + +Configure config.php according to your needs, also have a look into the LDAP and network settings in start.sh and stop.sh. + +# Usage # + +The basic command to run a test is: + +```# ./run-test.sh [phpscript]``` + +Yes, run it as root from within this directory. + +Example: + +``` +$ sudo ./run-test.sh lib/IntegrationTestAccessGroupsMatchFilter.php +71cbe88a4993e67066714d71c1cecc5ef26a54911a208103cb6294f90459e574 +c74dc0155db4efa7a0515d419528a8727bbc7596601cf25b0df05e348bd74895 +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +c74dc0155db4 osixia/phpldapadmin:0.5.1 "/sbin/my_init" 1 seconds ago Up Less than a second 80/tcp, 0.0.0.0:8443->443/tcp docker-phpldapadmin +71cbe88a4993 nickstenning/slapd:latest "/sbin/my_init" 1 seconds ago Up Less than a second 127.0.0.1:7770->389/tcp docker-slapd + +LDAP server now available under 127.0.0.1:7770 (internal IP is 172.17.0.78) +phpldapadmin now available under https://127.0.0.1:8443 + +created user : Alice Ealic +created group : RedGroup +created group : BlueGroup +created group : GreenGroup +created group : PurpleGroup +running case1 +running case2 +Tests succeeded +Stopping and resetting containers +docker-slapd +docker-phpldapadmin +docker-slapd +docker-phpldapadmin +``` + +# How it works # + +1. start.sh is executed which brings up a fresh and clean OpenLDAP in Docker. +2. The provided test script is executed. It also outputs results. +3. stop.sh is executed to shut down OpenLDAP + +# Beware # + +This is quick solution for basically one test case. With expension this mechanism should be improved as well. + +It does not run automatically, unless you do it. No integration with any testing framework. + +exceptionOnLostConnection.php is not part of this mechanism. Read its source and run it isolated. While you're at it, port it :þ + diff --git a/apps/user_ldap/tests/integration/run-test.sh b/apps/user_ldap/tests/integration/run-test.sh new file mode 100755 index 00000000000..e07e9b43408 --- /dev/null +++ b/apps/user_ldap/tests/integration/run-test.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +if [ $1 ] ; then + TESTSCRIPT=$1 +else + echo "No test file given" exit +fi + +if [ ! -e "$TESTSCRIPT" ] ; then + echo "Test file does not exist" + exit +fi + + +# sleep is necessary, otherwise the LDAP server cannot be connected to, yet. +setup-scripts/start.sh && sleep 2 && php -f "$TESTSCRIPT" +setup-scripts/stop.sh diff --git a/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroups.php b/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroups.php new file mode 100644 index 00000000000..68854de5571 --- /dev/null +++ b/apps/user_ldap/tests/integration/setup-scripts/createExplicitGroups.php @@ -0,0 +1,52 @@ +<?php + +if(php_sapi_name() !== 'cli') { + print('Only via CLI, please.'); + exit(1); +} + +include __DIR__ . '/config.php'; + +$cr = ldap_connect($host, $port); +ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3); +$ok = ldap_bind($cr, $adn, $apwd); + +if (!$ok) { + die(ldap_error($cr)); +} + +$ouName = 'Groups'; +$ouDN = 'ou=' . $ouName . ',' . $bdn; + +//creates an OU +if (true) { + $entry = []; + $entry['objectclass'][] = 'top'; + $entry['objectclass'][] = 'organizationalunit'; + $entry['ou'] = $ouName; + $b = ldap_add($cr, $ouDN, $entry); + if (!$b) { + die(ldap_error($cr)); + } +} + +$groups = ['RedGroup', 'BlueGroup', 'GreenGroup', 'PurpleGroup']; +// groupOfNames requires groups to have at least one member +// the member used is created by createExplicitUsers.php script +$omniMember = 'uid=alice,ou=Users,' . $bdn; + +foreach ($groups as $cn) { + $newDN = 'cn=' . $cn . ',' . $ouDN; + + $entry = []; + $entry['cn'] = $cn; + $entry['objectclass'][] = 'groupOfNames'; + $entry['member'][] = $omniMember; + + $ok = ldap_add($cr, $newDN, $entry); + if ($ok) { + echo('created group ' . ': ' . $entry['cn'] . PHP_EOL); + } else { + die(ldap_error($cr)); + } +} diff --git a/apps/user_ldap/tests/integration/setup-scripts/createExplicitUsers.php b/apps/user_ldap/tests/integration/setup-scripts/createExplicitUsers.php new file mode 100644 index 00000000000..ac21d48fd16 --- /dev/null +++ b/apps/user_ldap/tests/integration/setup-scripts/createExplicitUsers.php @@ -0,0 +1,54 @@ +<?php + +if(php_sapi_name() !== 'cli') { + print('Only via CLI, please.'); + exit(1); +} + +include __DIR__ . '/config.php'; + +$cr = ldap_connect($host, $port); +ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3); +$ok = ldap_bind($cr, $adn, $apwd); + +if (!$ok) { + die(ldap_error($cr)); +} + +$ouName = 'Users'; +$ouDN = 'ou=' . $ouName . ',' . $bdn; + +//creates on OU +if (true) { + $entry = []; + $entry['objectclass'][] = 'top'; + $entry['objectclass'][] = 'organizationalunit'; + $entry['ou'] = $ouName; + $b = ldap_add($cr, $ouDN, $entry); + if (!$b) { + die(ldap_error($cr)); + } +} + +$users = ['alice']; + +foreach ($users as $uid) { + $newDN = 'uid=' . $uid . ',' . $ouDN; + $fn = ucfirst($uid); + $sn = ucfirst(str_shuffle($uid)); // not so explicit but it's OK. + + $entry = []; + $entry['cn'] = $fn . ' ' . $sn; + $entry['objectclass'][] = 'inetOrgPerson'; + $entry['objectclass'][] = 'person'; + $entry['sn'] = $sn; + $entry['userPassword'] = $uid; + $entry['displayName'] = $sn . ', ' . $fn; + + $ok = ldap_add($cr, $newDN, $entry); + if ($ok) { + echo('created user ' . ': ' . $entry['cn'] . PHP_EOL); + } else { + die(ldap_error($cr)); + } +} diff --git a/lib/base.php b/lib/base.php index 829c2bcb866..8812d5698f1 100644 --- a/lib/base.php +++ b/lib/base.php @@ -730,8 +730,14 @@ class OC { // NOTE: This will be replaced to use OCP $userSession = self::$server->getUserSession(); $userSession->listen('\OC\User', 'postLogin', function () { - $cache = new \OC\Cache\File(); - $cache->gc(); + try { + $cache = new \OC\Cache\File(); + $cache->gc(); + } catch (\Exception $e) { + // a GC exception should not prevent users from using OC, + // so log the exception + \OC::$server->getLogger()->warning('Exception when running cache gc: ' . $e->getMessage(), array('app' => 'core')); + } }); } } diff --git a/lib/private/app.php b/lib/private/app.php index c506be1799b..1a32fcfcf77 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -1228,17 +1228,18 @@ class OC_App { // manages line breaks itself // first of all we split on empty lines - $paragraphs = preg_split("!\n[[:space:]]*\n!m", $data['description']); + $paragraphs = preg_split("!\n[[:space:]]*\n!mu", $data['description']); $result = []; foreach ($paragraphs as $value) { // replace multiple whitespace (tabs, space, newlines) inside a paragraph // with a single space - also trims whitespace - $result[] = trim(preg_replace('![[:space:]]+!m', ' ', $value)); + $result[] = trim(preg_replace('![[:space:]]+!mu', ' ', $value)); } // join the single paragraphs with a empty line in between $data['description'] = implode("\n\n", $result); + } return $data; diff --git a/lib/private/cache/file.php b/lib/private/cache/file.php index 32c00125764..69008c7fab5 100644 --- a/lib/private/cache/file.php +++ b/lib/private/cache/file.php @@ -177,9 +177,16 @@ class File implements ICache { } while (($file = readdir($dh)) !== false) { if ($file != '.' and $file != '..') { - $mtime = $storage->filemtime('/' . $file); - if ($mtime < $now) { - $storage->unlink('/' . $file); + try { + $mtime = $storage->filemtime('/' . $file); + if ($mtime < $now) { + $storage->unlink('/' . $file); + } + } catch (\OCP\Lock\LockedException $e) { + // ignore locked chunks + \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core')); + } catch (\OCP\Files\LockNotAcquiredException $e) { + \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core')); } } } diff --git a/lib/private/files/view.php b/lib/private/files/view.php index f2df2eb0f69..1706818f03e 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -79,6 +79,8 @@ class View { */ private $lockingProvider; + private $lockingEnabled; + /** * @param string $root * @throws \Exception If $root contains an invalid path @@ -94,6 +96,7 @@ class View { $this->fakeRoot = $root; $this->updater = new Updater($this); $this->lockingProvider = \OC::$server->getLockingProvider(); + $this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider); } public function getAbsolutePath($path = '/') { @@ -1026,7 +1029,7 @@ class View { } $unlockLater = false; - if ($operation === 'fopen' and is_resource($result)) { + if ($this->lockingEnabled && $operation === 'fopen' && is_resource($result)) { $unlockLater = true; $result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) { if (in_array('write', $hooks)) { diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 71390d99966..af7f78b9ff5 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -372,6 +372,22 @@ class Share extends Constants { if ($fileDependent && !self::isFileReachable($row['path'], $row['storage_id'])) { continue; } + if ($fileDependent && (int)$row['file_parent'] === -1) { + // if it is a mount point we need to get the path from the mount manager + $mountManager = \OC\Files\Filesystem::getMountManager(); + $mountPoint = $mountManager->findByStorageId($row['storage_id']); + if (!empty($mountPoint)) { + $path = $mountPoint[0]->getMountPoint(); + $path = trim($path, '/'); + $path = substr($path, strlen($owner) + 1); //normalize path to 'files/foo.txt` + $row['path'] = $path; + } else { + \OC::$server->getLogger()->warning( + 'Could not resolve mount point for ' . $row['storage_id'], + ['app' => 'OCP\Share'] + ); + } + } $shares[] = $row; } @@ -2290,7 +2306,7 @@ class Share extends Constants { if ($fileDependent) { $select = '`*PREFIX*share`.`id`, `*PREFIX*share`.`parent`, `share_type`, `path`, `storage`, ' . '`share_with`, `uid_owner` , `file_source`, `stime`, `*PREFIX*share`.`permissions`, ' - . '`*PREFIX*storages`.`id` AS `storage_id`'; + . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`'; } else { $select = '`id`, `parent`, `share_type`, `share_with`, `uid_owner`, `item_source`, `stime`, `*PREFIX*share`.`permissions`'; } @@ -2300,7 +2316,7 @@ class Share extends Constants { $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' . ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,' . ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`, ' - . '`*PREFIX*storages`.`id` AS `storage_id`'; + . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`'; } else { $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,' . ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`'; @@ -2317,7 +2333,7 @@ class Share extends Constants { . '`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,' . '`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`,' . '`stime`, `expiration`, `token`, `storage`, `mail_send`,' - . '`*PREFIX*storages`.`id` AS `storage_id`'; + . '`*PREFIX*storages`.`id` AS `storage_id`, `*PREFIX*filecache`.`parent` as `file_parent`'; } } } diff --git a/tests/lib/app.php b/tests/lib/app.php index 3f380f74fd2..9724c6e2344 100644 --- a/tests/lib/app.php +++ b/tests/lib/app.php @@ -503,6 +503,10 @@ class Test_App extends \Test\TestCase { ['description' => "This is a multiline test with some new lines"] ], [ + ['description' => hex2bin('5065726d657420646520732761757468656e7469666965722064616e732070697769676f20646972656374656d656e74206176656320736573206964656e74696669616e7473206f776e636c6f75642073616e73206c65732072657461706572206574206d657420c3a0206a6f757273206365757820636920656e20636173206465206368616e67656d656e74206465206d6f742064652070617373652e0d0a0d')], + ['description' => "Permet de s'authentifier dans piwigo directement avec ses identifiants owncloud sans les retaper et met à jours ceux ci en cas de changement de mot de passe."] + ], + [ ['not-a-description' => " \t This is a multiline \n test with \n \t some new lines "], ['not-a-description' => " \t This is a multiline \n test with \n \t some new lines "] ], @@ -513,9 +517,11 @@ class Test_App extends \Test\TestCase { * Test app info parser * * @dataProvider appDataProvider + * @param array $data + * @param array $expected */ - public function testParseAppInfo($data, $expected) { - $this->assertEquals($expected, \OC_App::parseAppInfo($data)); + public function testParseAppInfo(array $data, array $expected) { + $this->assertSame($expected, \OC_App::parseAppInfo($data)); } } diff --git a/tests/lib/cache/file.php b/tests/lib/cache/file.php index e31f84ee6f1..94001291d86 100644 --- a/tests/lib/cache/file.php +++ b/tests/lib/cache/file.php @@ -23,12 +23,22 @@ namespace Test\Cache; class FileCache extends \Test_Cache { - /** @var string */ + /** + * @var string + * */ private $user; - /** @var string */ + /** + * @var string + * */ private $datadir; - /** @var \OC\Files\Storage\Storage */ + /** + * @var \OC\Files\Storage\Storage + * */ private $storage; + /** + * @var \OC\Files\View + * */ + private $rootView; function skip() { //$this->skipUnless(OC_User::isLoggedIn()); @@ -59,13 +69,18 @@ class FileCache extends \Test_Cache { \OC_User::setUserId('test'); //set up the users dir - $rootView = new \OC\Files\View(''); - $rootView->mkdir('/test'); + $this->rootView = new \OC\Files\View(''); + $this->rootView->mkdir('/test'); $this->instance=new \OC\Cache\File(); + + // forces creation of cache folder for subsequent tests + $this->instance->set('hack', 'hack'); } protected function tearDown() { + $this->instance->remove('hack', 'hack'); + \OC_User::setUserId($this->user); \OC_Config::setValue('cachedirectory', $this->datadir); @@ -75,4 +90,73 @@ class FileCache extends \Test_Cache { parent::tearDown(); } + + private function setupMockStorage() { + $mockStorage = $this->getMock( + '\OC\Files\Storage\Local', + ['filemtime', 'unlink'], + [['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]] + ); + + \OC\Files\Filesystem::mount($mockStorage, array(), '/test/cache'); + + return $mockStorage; + } + + public function testGarbageCollectOldKeys() { + $mockStorage = $this->setupMockStorage(); + + $mockStorage->expects($this->atLeastOnce()) + ->method('filemtime') + ->will($this->returnValue(100)); + $mockStorage->expects($this->once()) + ->method('unlink') + ->with('key1') + ->will($this->returnValue(true)); + + $this->instance->set('key1', 'value1'); + $this->instance->gc(); + } + + public function testGarbageCollectLeaveRecentKeys() { + $mockStorage = $this->setupMockStorage(); + + $mockStorage->expects($this->atLeastOnce()) + ->method('filemtime') + ->will($this->returnValue(time() + 3600)); + $mockStorage->expects($this->never()) + ->method('unlink') + ->with('key1'); + $this->instance->set('key1', 'value1'); + $this->instance->gc(); + } + + public function lockExceptionProvider() { + return [ + [new \OCP\Lock\LockedException('key1')], + [new \OCP\Files\LockNotAcquiredException('key1', 1)], + ]; + } + + /** + * @dataProvider lockExceptionProvider + */ + public function testGarbageCollectIgnoreLockedKeys($testException) { + $mockStorage = $this->setupMockStorage(); + + $mockStorage->expects($this->atLeastOnce()) + ->method('filemtime') + ->will($this->returnValue(100)); + $mockStorage->expects($this->atLeastOnce()) + ->method('unlink') + ->will($this->onConsecutiveCalls( + $this->throwException($testException), + $this->returnValue(true) + )); + + $this->instance->set('key1', 'value1'); + $this->instance->set('key2', 'value2'); + + $this->instance->gc(); + } } diff --git a/version.php b/version.php index 1564f451bd3..c156c134974 100644 --- a/version.php +++ b/version.php @@ -22,10 +22,10 @@ // We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel // when updating major/minor version number. -$OC_Version=array(8, 1, 0, 7); +$OC_Version=array(8, 1, 0, 8); // The human readable string -$OC_VersionString='8.1 RC1'; +$OC_VersionString='8.1 RC2'; // The ownCloud channel $OC_Channel='git'; |