aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/private/connector/sabre/maintenanceplugin.php24
-rw-r--r--lib/private/files/storage/temporary.php2
-rw-r--r--lib/private/files/view.php40
-rw-r--r--lib/private/ocsclient.php1
-rw-r--r--lib/private/updater.php35
-rw-r--r--settings/controller/appsettingscontroller.php18
-rw-r--r--tests/files/file_put_contents.txt0
-rw-r--r--tests/lib/files/view.php624
-rw-r--r--tests/lib/ocsclienttest.php2
-rw-r--r--tests/lib/testcase.php16
-rw-r--r--tests/lib/testmoveablemountpoint.php49
-rw-r--r--tests/lib/updater.php386
12 files changed, 1075 insertions, 122 deletions
diff --git a/lib/private/connector/sabre/maintenanceplugin.php b/lib/private/connector/sabre/maintenanceplugin.php
index 9a596938097..21d711e844c 100644
--- a/lib/private/connector/sabre/maintenanceplugin.php
+++ b/lib/private/connector/sabre/maintenanceplugin.php
@@ -25,13 +25,16 @@
namespace OC\Connector\Sabre;
-class MaintenancePlugin extends \Sabre\DAV\ServerPlugin
-{
+use Sabre\DAV\Exception\ServiceUnavailable;
+use Sabre\DAV\Server;
+use Sabre\DAV\ServerPlugin;
+
+class MaintenancePlugin extends ServerPlugin {
/**
* Reference to main server object
*
- * @var \Sabre\DAV\Server
+ * @var Server
*/
private $server;
@@ -43,11 +46,10 @@ class MaintenancePlugin extends \Sabre\DAV\ServerPlugin
*
* This method should set up the required event subscriptions.
*
- * @param \Sabre\DAV\Server $server
+ * @param Server $server
* @return void
*/
- public function initialize(\Sabre\DAV\Server $server) {
-
+ public function initialize(Server $server) {
$this->server = $server;
$this->server->on('beforeMethod', array($this, 'checkMaintenanceMode'), 10);
}
@@ -56,19 +58,19 @@ class MaintenancePlugin extends \Sabre\DAV\ServerPlugin
* This method is called before any HTTP method and returns http status code 503
* in case the system is in maintenance mode.
*
- * @throws \Sabre\DAV\Exception\ServiceUnavailable
+ * @throws ServiceUnavailable
* @internal param string $method
* @return bool
*/
public function checkMaintenanceMode() {
if (\OC::$server->getSystemConfig()->getValue('singleuser', false)) {
- throw new \Sabre\DAV\Exception\ServiceUnavailable();
+ throw new ServiceUnavailable('System in single user mode.');
}
- if (\OC_Config::getValue('maintenance', false)) {
- throw new \Sabre\DAV\Exception\ServiceUnavailable();
+ if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
+ throw new ServiceUnavailable('System in maintenance mode.');
}
if (\OC::checkUpgrade(false)) {
- throw new \Sabre\DAV\Exception\ServiceUnavailable('Upgrade needed');
+ throw new ServiceUnavailable('Upgrade needed');
}
return true;
diff --git a/lib/private/files/storage/temporary.php b/lib/private/files/storage/temporary.php
index 0f259905c80..ca348313e45 100644
--- a/lib/private/files/storage/temporary.php
+++ b/lib/private/files/storage/temporary.php
@@ -27,7 +27,7 @@ namespace OC\Files\Storage;
* local storage backend in temporary folder for testing purpose
*/
class Temporary extends Local{
- public function __construct($arguments) {
+ public function __construct($arguments = null) {
parent::__construct(array('datadir' => \OC_Helper::tmpFolder()));
}
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index 61adc6246fb..0c3bc54a41d 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -559,11 +559,12 @@ class View {
$this->updater->update($path);
- $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
+ $this->changeLock($path, ILockingProvider::LOCK_SHARED);
if ($this->shouldEmitHooks($path) && $result !== false) {
$this->emit_file_hooks_post($exists, $path);
}
+ $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
return $result;
} else {
$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
@@ -615,6 +616,7 @@ class View {
public function rename($path1, $path2) {
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
+ $result = false;
if (
Filesystem::isValidPath($path2)
and Filesystem::isValidPath($path1)
@@ -695,8 +697,8 @@ class View {
}
}
- $this->unlockFile($path1, ILockingProvider::LOCK_EXCLUSIVE, true);
- $this->unlockFile($path2, ILockingProvider::LOCK_EXCLUSIVE, true);
+ $this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
+ $this->changeLock($path2, ILockingProvider::LOCK_SHARED, true);
if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
if ($this->shouldEmitHooks()) {
@@ -714,15 +716,11 @@ class View {
);
}
}
- return $result;
- } else {
- $this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
- $this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true);
- return false;
}
- } else {
- return false;
+ $this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
+ $this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true);
}
+ return $result;
}
/**
@@ -737,6 +735,7 @@ class View {
public function copy($path1, $path2, $preserveMtime = false) {
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
+ $result = false;
if (
Filesystem::isValidPath($path2)
and Filesystem::isValidPath($path1)
@@ -788,8 +787,7 @@ class View {
$this->updater->update($path2);
- $this->unlockFile($path2, ILockingProvider::LOCK_EXCLUSIVE);
- $this->unlockFile($path1, ILockingProvider::LOCK_SHARED);
+ $this->changeLock($path2, ILockingProvider::LOCK_SHARED);
if ($this->shouldEmitHooks() && $result !== false) {
\OC_Hook::emit(
@@ -802,15 +800,12 @@ class View {
);
$this->emit_file_hooks_post($exists, $path2);
}
- return $result;
- } else {
+
$this->unlockFile($path2, ILockingProvider::LOCK_SHARED);
$this->unlockFile($path1, ILockingProvider::LOCK_SHARED);
- return false;
}
- } else {
- return false;
}
+ return $result;
}
/**
@@ -1025,7 +1020,9 @@ class View {
$this->changeLock($path, ILockingProvider::LOCK_SHARED);
}
+ $unlockLater = false;
if ($operation === 'fopen' and is_resource($result)) {
+ $unlockLater = true;
$result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) {
if (in_array('write', $hooks)) {
$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
@@ -1033,16 +1030,19 @@ class View {
$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
}
});
- } else if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) {
- $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
}
-
if ($this->shouldEmitHooks($path) && $result !== false) {
if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open
$this->runHooks($hooks, $path, true);
}
}
+
+ if (!$unlockLater
+ && (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks))
+ ) {
+ $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
+ }
return $result;
} else {
$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
diff --git a/lib/private/ocsclient.php b/lib/private/ocsclient.php
index 9fa4aebb5e4..9fd3bb13733 100644
--- a/lib/private/ocsclient.php
+++ b/lib/private/ocsclient.php
@@ -293,6 +293,7 @@ class OCSClient {
$app['description'] = (string)$tmp->description;
$app['detailpage'] = (string)$tmp->detailpage;
$app['score'] = (int)$tmp->score;
+ $app['level'] = (int)$tmp->approved;
return $app;
}
diff --git a/lib/private/updater.php b/lib/private/updater.php
index 2894a82338f..fa9c1a5176a 100644
--- a/lib/private/updater.php
+++ b/lib/private/updater.php
@@ -74,7 +74,9 @@ class Updater extends BasicEmitter {
* @param IConfig $config
* @param ILogger $log
*/
- public function __construct(HTTPHelper $httpHelper, IConfig $config, ILogger $log = null) {
+ public function __construct(HTTPHelper $httpHelper,
+ IConfig $config,
+ ILogger $log = null) {
$this->httpHelper = $httpHelper;
$this->log = $log;
$this->config = $config;
@@ -127,12 +129,12 @@ class Updater extends BasicEmitter {
}
if (is_null($updaterUrl)) {
- $updaterUrl = 'https://apps.owncloud.com/updater.php';
+ $updaterUrl = 'https://updates.owncloud.com/server/';
}
$this->config->setAppValue('core', 'lastupdatedat', time());
- if ($this->config->getAppValue('core', 'installedat', '') == '') {
+ if ($this->config->getAppValue('core', 'installedat', '') === '') {
$this->config->setAppValue('core', 'installedat', microtime(true));
}
@@ -147,22 +149,20 @@ class Updater extends BasicEmitter {
//fetch xml data from updater
$url = $updaterUrl . '?version=' . $versionString;
- // set a sensible timeout of 10 sec to stay responsive even if the update server is down.
-
- $tmp = array();
+ $tmp = [];
$xml = $this->httpHelper->getUrlContent($url);
if ($xml) {
$loadEntities = libxml_disable_entity_loader(true);
$data = @simplexml_load_string($xml);
libxml_disable_entity_loader($loadEntities);
if ($data !== false) {
- $tmp['version'] = $data->version;
- $tmp['versionstring'] = $data->versionstring;
- $tmp['url'] = $data->url;
- $tmp['web'] = $data->web;
+ $tmp['version'] = (string)$data->version;
+ $tmp['versionstring'] = (string)$data->versionstring;
+ $tmp['url'] = (string)$data->url;
+ $tmp['web'] = (string)$data->web;
}
} else {
- $data = array();
+ $data = [];
}
// Cache the result
@@ -360,7 +360,6 @@ class Updater extends BasicEmitter {
include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
}
-
/**
* upgrades all apps within a major ownCloud upgrade. Also loads "priority"
* (types authentication, filesystem, logging, in that order) afterwards.
@@ -411,6 +410,9 @@ class Updater extends BasicEmitter {
* ownCloud version. disable them if not.
* This is important if you upgrade ownCloud and have non ported 3rd
* party apps installed.
+ *
+ * @return array
+ * @throws \Exception
*/
private function checkAppsRequirements() {
$isCoreUpgrade = $this->isCodeUpgrade();
@@ -447,6 +449,9 @@ class Updater extends BasicEmitter {
return $disabledApps;
}
+ /**
+ * @return bool
+ */
private function isCodeUpgrade() {
$installedVersion = $this->config->getSystemValue('version', '0.0.0');
$currentVersion = implode('.', OC_Util::getVersion());
@@ -456,7 +461,11 @@ class Updater extends BasicEmitter {
return false;
}
- private function upgradeAppStoreApps($disabledApps) {
+ /**
+ * @param array $disabledApps
+ * @throws \Exception
+ */
+ private function upgradeAppStoreApps(array $disabledApps) {
foreach($disabledApps as $app) {
if (OC_Installer::isUpdateAvailable($app)) {
$ocsId = \OC::$server->getConfig()->getAppValue($app, 'ocsid', '');
diff --git a/settings/controller/appsettingscontroller.php b/settings/controller/appsettingscontroller.php
index 53570a2a35f..f62ced23ff8 100644
--- a/settings/controller/appsettingscontroller.php
+++ b/settings/controller/appsettingscontroller.php
@@ -169,6 +169,15 @@ class AppSettingsController extends Controller {
}
return ($a < $b) ? -1 : 1;
});
+ foreach($apps as $key => $app) {
+ if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) {
+ $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid']);
+
+ if(array_key_exists('level', $remoteAppEntry)) {
+ $apps[$key]['level'] = $remoteAppEntry['level'];
+ }
+ }
+ }
break;
// not-installed apps
case 1:
@@ -176,6 +185,15 @@ class AppSettingsController extends Controller {
$apps = array_filter($apps, function ($app) {
return !$app['active'];
});
+ foreach($apps as $key => $app) {
+ if(!array_key_exists('level', $app) && array_key_exists('ocsid', $app)) {
+ $remoteAppEntry = $this->ocsClient->getApplication($app['ocsid']);
+
+ if(array_key_exists('level', $remoteAppEntry)) {
+ $apps[$key]['level'] = $remoteAppEntry['level'];
+ }
+ }
+ }
usort($apps, function ($a, $b) {
$a = (string)$a['name'];
$b = (string)$b['name'];
diff --git a/tests/files/file_put_contents.txt b/tests/files/file_put_contents.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/tests/files/file_put_contents.txt
diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php
index 42768a0b274..52273c15f1a 100644
--- a/tests/lib/files/view.php
+++ b/tests/lib/files/view.php
@@ -51,15 +51,16 @@ class View extends \Test\TestCase {
protected function setUp() {
parent::setUp();
+ \OC_Hook::clear();
\OC_User::clearBackends();
\OC_User::useBackend(new \OC_User_Dummy());
//login
\OC_User::createUser('test', 'test');
- $this->user = \OC_User::getUser();
$this->loginAsUser('test');
+ $this->user = \OC_User::getUser();
// clear mounts but somehow keep the root storage
// that was initialized above...
\OC\Files\Filesystem::clearMounts();
@@ -1350,4 +1351,625 @@ class View extends \Test\TestCase {
$defaultRootValue->setValue($oldRoot);
$this->assertEquals($shouldEmit, $result);
}
+
+
+ public function basicOperationProviderForLocks() {
+ return [
+ // --- write hook ----
+ [
+ 'touch',
+ ['touch-create.txt'],
+ 'touch-create.txt',
+ 'create',
+ ILockingProvider::LOCK_SHARED,
+ ILockingProvider::LOCK_EXCLUSIVE,
+ ILockingProvider::LOCK_SHARED,
+ ],
+ [
+ 'fopen',
+ ['test-write.txt', 'w'],
+ 'test-write.txt',
+ 'write',
+ ILockingProvider::LOCK_SHARED,
+ ILockingProvider::LOCK_EXCLUSIVE,
+ null,
+ // exclusive lock stays until fclose
+ ILockingProvider::LOCK_EXCLUSIVE,
+ ],
+ [
+ 'mkdir',
+ ['newdir'],
+ 'newdir',
+ 'write',
+ ILockingProvider::LOCK_SHARED,
+ ILockingProvider::LOCK_EXCLUSIVE,
+ ILockingProvider::LOCK_SHARED,
+ ],
+ [
+ 'file_put_contents',
+ ['file_put_contents.txt', 'blah'],
+ 'file_put_contents.txt',
+ 'write',
+ ILockingProvider::LOCK_SHARED,
+ ILockingProvider::LOCK_EXCLUSIVE,
+ ILockingProvider::LOCK_SHARED,
+ ],
+
+ // ---- delete hook ----
+ [
+ 'rmdir',
+ ['dir'],
+ 'dir',
+ 'delete',
+ ILockingProvider::LOCK_SHARED,
+ ILockingProvider::LOCK_EXCLUSIVE,
+ ILockingProvider::LOCK_SHARED,
+ ],
+ [
+ 'unlink',
+ ['test.txt'],
+ 'test.txt',
+ 'delete',
+ ILockingProvider::LOCK_SHARED,
+ ILockingProvider::LOCK_EXCLUSIVE,
+ ILockingProvider::LOCK_SHARED,
+ ],
+
+ // ---- read hook (no post hooks) ----
+ [
+ 'file_get_contents',
+ ['test.txt'],
+ 'test.txt',
+ 'read',
+ ILockingProvider::LOCK_SHARED,
+ ILockingProvider::LOCK_SHARED,
+ null,
+ ],
+ [
+ 'fopen',
+ ['test.txt', 'r'],
+ 'test.txt',
+ 'read',
+ ILockingProvider::LOCK_SHARED,
+ ILockingProvider::LOCK_SHARED,
+ null,
+ ],
+ [
+ 'opendir',
+ ['dir'],
+ 'dir',
+ 'read',
+ ILockingProvider::LOCK_SHARED,
+ ILockingProvider::LOCK_SHARED,
+ null,
+ ],
+
+ // ---- no lock, touch hook ---
+ ['touch', ['test.txt'], 'test.txt', 'touch', null, null, null],
+
+ // ---- no hooks, no locks ---
+ ['is_dir', ['dir'], 'dir', null],
+ ['is_file', ['dir'], 'dir', null],
+ ['stat', ['dir'], 'dir', null],
+ ['filetype', ['dir'], 'dir', null],
+ ['filesize', ['dir'], 'dir', null],
+ ['isCreatable', ['dir'], 'dir', null],
+ ['isReadable', ['dir'], 'dir', null],
+ ['isUpdatable', ['dir'], 'dir', null],
+ ['isDeletable', ['dir'], 'dir', null],
+ ['isSharable', ['dir'], 'dir', null],
+ ['file_exists', ['dir'], 'dir', null],
+ ['filemtime', ['dir'], 'dir', null],
+ ];
+ }
+
+ /**
+ * Test whether locks are set before and after the operation
+ *
+ * @dataProvider basicOperationProviderForLocks
+ *
+ * @param string $operation operation name on the view
+ * @param array $operationArgs arguments for the operation
+ * @param string $lockedPath path of the locked item to check
+ * @param string $hookType hook type
+ * @param int $expectedLockBefore expected lock during pre hooks
+ * @param int $expectedLockduring expected lock during operation
+ * @param int $expectedLockAfter expected lock during post hooks
+ * @param int $expectedStrayLock expected lock after returning, should
+ * be null (unlock) for most operations
+ */
+ public function testLockBasicOperation(
+ $operation,
+ $operationArgs,
+ $lockedPath,
+ $hookType,
+ $expectedLockBefore = ILockingProvider::LOCK_SHARED,
+ $expectedLockDuring = ILockingProvider::LOCK_SHARED,
+ $expectedLockAfter = ILockingProvider::LOCK_SHARED,
+ $expectedStrayLock = null
+ ) {
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
+ ->setMethods([$operation])
+ ->getMock();
+
+ \OC\Files\Filesystem::mount($storage, array(), $this->user . '/');
+
+ // work directly on disk because mkdir might be mocked
+ $realPath = $storage->getSourcePath('');
+ mkdir($realPath . '/files');
+ mkdir($realPath . '/files/dir');
+ file_put_contents($realPath . '/files/test.txt', 'blah');
+ $storage->getScanner()->scan('files');
+
+ $storage->expects($this->once())
+ ->method($operation)
+ ->will($this->returnCallback(
+ function() use ($view, $lockedPath, &$lockTypeDuring){
+ $lockTypeDuring = $this->getFileLockType($view, $lockedPath);
+
+ return true;
+ }
+ ));
+
+ $this->assertNull($this->getFileLockType($view, $lockedPath), 'File not locked before operation');
+
+ $this->connectMockHooks($hookType, $view, $lockedPath, $lockTypePre, $lockTypePost);
+
+ // do operation
+ call_user_func_array(array($view, $operation), $operationArgs);
+
+ if ($hookType !== null) {
+ $this->assertEquals($expectedLockBefore, $lockTypePre, 'File locked properly during pre-hook');
+ $this->assertEquals($expectedLockAfter, $lockTypePost, 'File locked properly during post-hook');
+ $this->assertEquals($expectedLockDuring, $lockTypeDuring, 'File locked properly during operation');
+ } else {
+ $this->assertNull($lockTypeDuring, 'File not locked during operation');
+ }
+
+ $this->assertEquals($expectedStrayLock, $this->getFileLockType($view, $lockedPath));
+ }
+
+ /**
+ * Test locks for file_put_content with stream.
+ * This code path uses $storage->fopen instead
+ */
+ public function testLockFilePutContentWithStream() {
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+
+ $path = 'test_file_put_contents.txt';
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
+ ->setMethods(['fopen'])
+ ->getMock();
+
+ \OC\Files\Filesystem::mount($storage, array(), $this->user . '/');
+ $storage->mkdir('files');
+
+ $storage->expects($this->once())
+ ->method('fopen')
+ ->will($this->returnCallback(
+ function() use ($view, $path, &$lockTypeDuring){
+ $lockTypeDuring = $this->getFileLockType($view, $path);
+
+ return fopen('php://temp', 'r+');
+ }
+ ));
+
+ $this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost);
+
+ $this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation');
+
+ // do operation
+ $view->file_put_contents($path, fopen('php://temp', 'r+'));
+
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook');
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePost, 'File locked properly during post-hook');
+ $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation');
+
+ $this->assertNull($this->getFileLockType($view, $path));
+ }
+
+ /**
+ * Test locks for fopen with fclose at the end
+ */
+ public function testLockFopen() {
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+
+ $path = 'test_file_put_contents.txt';
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
+ ->setMethods(['fopen'])
+ ->getMock();
+
+ \OC\Files\Filesystem::mount($storage, array(), $this->user . '/');
+ $storage->mkdir('files');
+
+ $storage->expects($this->once())
+ ->method('fopen')
+ ->will($this->returnCallback(
+ function() use ($view, $path, &$lockTypeDuring){
+ $lockTypeDuring = $this->getFileLockType($view, $path);
+
+ return fopen('php://temp', 'r+');
+ }
+ ));
+
+ $this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost);
+
+ $this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation');
+
+ // do operation
+ $res = $view->fopen($path, 'w');
+
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook');
+ $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation');
+ $this->assertNull(null, $lockTypePost, 'No post hook, no lock check possible');
+
+ $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File still locked after fopen');
+
+ fclose($res);
+
+ $this->assertNull($this->getFileLockType($view, $path), 'File unlocked after fclose');
+ }
+
+ /**
+ * Test locks for fopen with fclose at the end
+ *
+ * @dataProvider basicOperationProviderForLocks
+ *
+ * @param string $operation operation name on the view
+ * @param array $operationArgs arguments for the operation
+ * @param string $path path of the locked item to check
+ */
+ public function testLockBasicOperationUnlocksAfterException(
+ $operation,
+ $operationArgs,
+ $path
+ ) {
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
+ ->setMethods([$operation])
+ ->getMock();
+
+ \OC\Files\Filesystem::mount($storage, array(), $this->user . '/');
+
+ // work directly on disk because mkdir might be mocked
+ $realPath = $storage->getSourcePath('');
+ mkdir($realPath . '/files');
+ mkdir($realPath . '/files/dir');
+ file_put_contents($realPath . '/files/test.txt', 'blah');
+ $storage->getScanner()->scan('files');
+
+ $storage->expects($this->once())
+ ->method($operation)
+ ->will($this->returnCallback(
+ function() {
+ throw new \Exception('Simulated exception');
+ }
+ ));
+
+ $thrown = false;
+ try {
+ call_user_func_array(array($view, $operation), $operationArgs);
+ } catch (\Exception $e) {
+ $thrown = true;
+ $this->assertEquals('Simulated exception', $e->getMessage());
+ }
+ $this->assertTrue($thrown, 'Exception was rethrown');
+ $this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception');
+ }
+
+ /**
+ * Test locks for fopen with fclose at the end
+ *
+ * @dataProvider basicOperationProviderForLocks
+ *
+ * @param string $operation operation name on the view
+ * @param array $operationArgs arguments for the operation
+ * @param string $path path of the locked item to check
+ * @param string $hookType hook type
+ */
+ public function testLockBasicOperationUnlocksAfterCancelledHook(
+ $operation,
+ $operationArgs,
+ $path,
+ $hookType
+ ) {
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
+ ->setMethods([$operation])
+ ->getMock();
+
+ \OC\Files\Filesystem::mount($storage, array(), $this->user . '/');
+ $storage->mkdir('files');
+
+ \OCP\Util::connectHook(
+ \OC\Files\Filesystem::CLASSNAME,
+ $hookType,
+ '\Test\HookHelper',
+ 'cancellingCallback'
+ );
+
+ call_user_func_array(array($view, $operation), $operationArgs);
+
+ $this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception');
+ }
+
+ public function lockFileRenameOrCopyDataProvider() {
+ return [
+ ['rename', ILockingProvider::LOCK_EXCLUSIVE],
+ ['copy', ILockingProvider::LOCK_SHARED],
+ ];
+ }
+
+ /**
+ * Test locks for rename or copy operation
+ *
+ * @dataProvider lockFileRenameOrCopyDataProvider
+ *
+ * @param string $operation operation to be done on the view
+ * @param int $expectedLockTypeSourceDuring expected lock type on source file during
+ * the operation
+ */
+ public function testLockFileRename($operation, $expectedLockTypeSourceDuring) {
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
+ ->setMethods([$operation])
+ ->getMock();
+
+ $sourcePath = 'original.txt';
+ $targetPath = 'target.txt';
+
+ \OC\Files\Filesystem::mount($storage, array(), $this->user . '/');
+ $storage->mkdir('files');
+ $view->file_put_contents($sourcePath, 'meh');
+
+ $storage->expects($this->once())
+ ->method($operation)
+ ->will($this->returnCallback(
+ function() use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring){
+ $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
+ $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
+
+ return true;
+ }
+ ));
+
+ $this->connectMockHooks($operation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
+ $this->connectMockHooks($operation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
+
+ $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
+ $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
+
+ $view->$operation($sourcePath, $targetPath);
+
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook');
+ $this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation');
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook');
+
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook');
+ $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation');
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook');
+
+ $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
+ $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
+ }
+
+ public function lockFileRenameOrCopyCrossStorageDataProvider() {
+ return [
+ ['rename', 'moveFromStorage', ILockingProvider::LOCK_EXCLUSIVE],
+ ['copy', 'copyFromStorage', ILockingProvider::LOCK_SHARED],
+ ];
+ }
+
+ /**
+ * Test locks for rename or copy operation cross-storage
+ *
+ * @dataProvider lockFileRenameOrCopyCrossStorageDataProvider
+ *
+ * @param string $viewOperation operation to be done on the view
+ * @param string $storageOperation operation to be mocked on the storage
+ * @param int $expectedLockTypeSourceDuring expected lock type on source file during
+ * the operation
+ */
+ public function testLockFileRenameCrossStorage($viewOperation, $storageOperation, $expectedLockTypeSourceDuring) {
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+
+ $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
+ ->setMethods([$storageOperation])
+ ->getMock();
+ $storage2 = $this->getMockBuilder('\OC\Files\Storage\Temporary')
+ ->setMethods([$storageOperation])
+ ->getMock();
+
+ $sourcePath = 'original.txt';
+ $targetPath = 'substorage/target.txt';
+
+ \OC\Files\Filesystem::mount($storage, array(), $this->user . '/');
+ \OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage');
+ $storage->mkdir('files');
+ $view->file_put_contents($sourcePath, 'meh');
+
+ $storage->expects($this->never())
+ ->method($storageOperation);
+ $storage2->expects($this->once())
+ ->method($storageOperation)
+ ->will($this->returnCallback(
+ function() use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring){
+ $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath);
+ $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath);
+
+ return true;
+ }
+ ));
+
+ $this->connectMockHooks($viewOperation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost);
+ $this->connectMockHooks($viewOperation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost);
+
+ $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation');
+ $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation');
+
+ $view->$viewOperation($sourcePath, $targetPath);
+
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook');
+ $this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation');
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook');
+
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook');
+ $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation');
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook');
+
+ $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation');
+ $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation');
+ }
+
+ /**
+ * Test locks when moving a mount point
+ */
+ public function testLockMoveMountPoint() {
+ $this->loginAsUser('test');
+
+ $subStorage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
+ ->setMethods([])
+ ->getMock();
+
+ $mount = $this->getMock(
+ '\Test\TestMoveableMountPoint',
+ ['moveMount'],
+ [$subStorage, $this->user . '/files/substorage']
+ );
+
+ $mountProvider = $this->getMock('\OCP\Files\Config\IMountProvider');
+ $mountProvider->expects($this->once())
+ ->method('getMountsForUser')
+ ->will($this->returnValue([$mount]));
+
+ $mountProviderCollection = \OC::$server->getMountProviderCollection();
+ $mountProviderCollection->registerProvider($mountProvider);
+
+ $view = new \OC\Files\View('/' . $this->user . '/files/');
+ $view->mkdir('subdir');
+
+ $sourcePath = 'substorage';
+ $targetPath = 'subdir/substorage_moved';
+
+ $mount->expects($this->once())
+ ->method('moveMount')
+ ->will($this->returnCallback(
+ function($target) use ($mount, $view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring, &$lockTypeSharedRootDuring){
+ $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath, true);
+ $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath, true);
+
+ $lockTypeSharedRootDuring = $this->getFileLockType($view, $sourcePath, false);
+
+ $mount->setMountPoint($target);
+
+ return true;
+ }
+ ));
+
+ $this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost, true);
+ $this->connectMockHooks('rename', $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost, true);
+ // in pre-hook, mount point is still on $sourcePath
+ $this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSharedRootPre, $dummy, false);
+ // in post-hook, mount point is now on $targetPath
+ $this->connectMockHooks('rename', $view, $targetPath, $dummy, $lockTypeSharedRootPost, false);
+
+ $this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked before operation');
+ $this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked before operation');
+ $this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked before operation');
+
+ $view->rename($sourcePath, $targetPath);
+
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source path locked properly during pre-hook');
+ $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeSourceDuring, 'Source path locked properly during operation');
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source path locked properly during post-hook');
+
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target path locked properly during pre-hook');
+ $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target path locked properly during operation');
+ $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target path locked properly during post-hook');
+
+ $this->assertNull($lockTypeSharedRootPre, 'Shared storage root not locked during pre-hook');
+ $this->assertNull($lockTypeSharedRootDuring, 'Shared storage root not locked during move');
+ $this->assertNull($lockTypeSharedRootPost, 'Shared storage root not locked during post-hook');
+
+ $this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked after operation');
+ $this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked after operation');
+ $this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked after operation');
+
+ \Test\TestCase::invokePrivate($mountProviderCollection, 'providers', [[]]);
+ }
+
+ /**
+ * Connect hook callbacks for hook type
+ *
+ * @param string $hookType hook type or null for none
+ * @param \OC\Files\View $view view to check the lock on
+ * @param string $path path for which to check the lock
+ * @param int $lockTypePre variable to receive lock type that was active in the pre-hook
+ * @param int $lockTypePost variable to receive lock type that was active in the post-hook
+ * @param bool $onMountPoint true to check the mount point instead of the
+ * mounted storage
+ */
+ private function connectMockHooks($hookType, $view, $path, &$lockTypePre, &$lockTypePost, $onMountPoint = false) {
+ if ($hookType === null) {
+ return;
+ }
+
+ $eventHandler = $this->getMockBuilder('\stdclass')
+ ->setMethods(['preCallback', 'postCallback'])
+ ->getMock();
+
+ $eventHandler->expects($this->any())
+ ->method('preCallback')
+ ->will($this->returnCallback(
+ function() use ($view, $path, $onMountPoint, &$lockTypePre){
+ $lockTypePre = $this->getFileLockType($view, $path, $onMountPoint);
+ }
+ ));
+ $eventHandler->expects($this->any())
+ ->method('postCallback')
+ ->will($this->returnCallback(
+ function() use ($view, $path, $onMountPoint, &$lockTypePost){
+ $lockTypePost = $this->getFileLockType($view, $path, $onMountPoint);
+ }
+ ));
+
+ if ($hookType !== null) {
+ \OCP\Util::connectHook(
+ \OC\Files\Filesystem::CLASSNAME,
+ $hookType,
+ $eventHandler,
+ 'preCallback'
+ );
+ \OCP\Util::connectHook(
+ \OC\Files\Filesystem::CLASSNAME,
+ 'post_' . $hookType,
+ $eventHandler,
+ 'postCallback'
+ );
+ }
+ }
+
+ /**
+ * Returns the file lock type
+ *
+ * @param \OC\Files\View $view view
+ * @param string $path path
+ * @param bool $onMountPoint true to check the mount point instead of the
+ * mounted storage
+ *
+ * @return int lock type or null if file was not locked
+ */
+ private function getFileLockType(\OC\Files\View $view, $path, $onMountPoint = false) {
+ if ($this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE, $onMountPoint)) {
+ return ILockingProvider::LOCK_EXCLUSIVE;
+ } else if ($this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED, $onMountPoint)) {
+ return ILockingProvider::LOCK_SHARED;
+ }
+ return null;
+ }
}
diff --git a/tests/lib/ocsclienttest.php b/tests/lib/ocsclienttest.php
index b8c4ed2f7f4..80102eb62ee 100644
--- a/tests/lib/ocsclienttest.php
+++ b/tests/lib/ocsclienttest.php
@@ -737,6 +737,7 @@ class OCSClientTest extends \Test\TestCase {
<downloadpackagename1></downloadpackagename1>
<downloadrepository1></downloadrepository1>
<downloadsize1>1</downloadsize1>
+ <approved>200</approved>
</content>
</data>
</ocs>
@@ -776,6 +777,7 @@ class OCSClientTest extends \Test\TestCase {
'changed' => 1404743680,
'description' => 'Placeholder for future updates',
'score' => 50,
+ 'level' => 200,
];
$this->assertSame($expected, $this->ocsClient->getApplication('MyId', [8, 1, 0, 7]));
}
diff --git a/tests/lib/testcase.php b/tests/lib/testcase.php
index d385a903d1e..407c5165140 100644
--- a/tests/lib/testcase.php
+++ b/tests/lib/testcase.php
@@ -104,6 +104,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
self::tearDownAfterClassCleanFileCache();
self::tearDownAfterClassCleanStrayDataFiles($dataDir);
self::tearDownAfterClassCleanStrayHooks();
+ self::tearDownAfterClassCleanStrayLocks();
parent::tearDownAfterClass();
}
@@ -197,6 +198,13 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
}
/**
+ * Clean up the list of locks
+ */
+ static protected function tearDownAfterClassCleanStrayLocks() {
+ \OC::$server->getLockingProvider()->releaseAll();
+ }
+
+ /**
* Login and setup FS as a given user,
* sets the given user as the current user.
*
@@ -249,11 +257,13 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
* @param \OC\Files\View $view view
* @param string $path path to check
* @param int $type lock type
+ * @param bool $onMountPoint true to check the mount point instead of the
+ * mounted storage
*
* @return boolean true if the file is locked with the
* given type, false otherwise
*/
- protected function isFileLocked($view, $path, $type) {
+ protected function isFileLocked($view, $path, $type, $onMountPoint = false) {
// Note: this seems convoluted but is necessary because
// the format of the lock key depends on the storage implementation
// (in our case mostly md5)
@@ -266,10 +276,10 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase {
$checkType = \OCP\Lock\ILockingProvider::LOCK_SHARED;
}
try {
- $view->lockFile($path, $checkType);
+ $view->lockFile($path, $checkType, $onMountPoint);
// no exception, which means the lock of $type is not set
// clean up
- $view->unlockFile($path, $checkType);
+ $view->unlockFile($path, $checkType, $onMountPoint);
return false;
} catch (\OCP\Lock\LockedException $e) {
// we could not acquire the counter-lock, which means
diff --git a/tests/lib/testmoveablemountpoint.php b/tests/lib/testmoveablemountpoint.php
new file mode 100644
index 00000000000..262016b76c1
--- /dev/null
+++ b/tests/lib/testmoveablemountpoint.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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 Test;
+
+use OC\Files\Mount;
+
+/**
+ * Test moveable mount for mocking
+ */
+class TestMoveableMountPoint extends Mount\MountPoint implements Mount\MoveableMount {
+
+ /**
+ * Move the mount point to $target
+ *
+ * @param string $target the target mount point
+ * @return bool
+ */
+ public function moveMount($target) {
+ $this->setMountPoint($target);
+ }
+
+ /**
+ * Remove the mount points
+ *
+ * @return mixed
+ * @return bool
+ */
+ public function removeMount() {
+ }
+}
diff --git a/tests/lib/updater.php b/tests/lib/updater.php
index 13b45b3d8e7..8d6a9d65b27 100644
--- a/tests/lib/updater.php
+++ b/tests/lib/updater.php
@@ -1,107 +1,347 @@
<?php
/**
- * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com>
- * This file is licensed under the Affero General Public License version 3 or
- * later.
- * See the COPYING-README file.
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @author Victor Dubiniuk <dubiniuk@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @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 OC;
+use OCP\IConfig;
+use OCP\ILogger;
+
class UpdaterTest extends \Test\TestCase {
+ /** @var IConfig */
+ private $config;
+ /** @var HTTPHelper */
+ private $httpHelper;
+ /** @var ILogger */
+ private $logger;
+ /** @var Updater */
+ private $updater;
- public function versionCompatibilityTestData() {
- return array(
- array('1.0.0.0', '2.2.0', true),
- array('1.1.1.1', '2.0.0', true),
- array('5.0.3', '4.0.3', false),
- array('12.0.3', '13.4.5', true),
- array('1', '2', true),
- array('2', '2', true),
- array('6.0.5', '6.0.6', true),
- array('5.0.6', '7.0.4', false)
+ public function setUp() {
+ parent::setUp();
+ $this->config = $this->getMockBuilder('\\OCP\\IConfig')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->httpHelper = $this->getMockBuilder('\\OC\\HTTPHelper')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->logger = $this->getMockBuilder('\\OCP\\ILogger')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->updater = new Updater(
+ $this->httpHelper,
+ $this->config,
+ $this->logger
);
}
/**
+ * @param string $baseUrl
+ * @return string
+ */
+ private function buildUpdateUrl($baseUrl) {
+ return $baseUrl . '?version='.implode('x', \OC_Util::getVersion()).'xinstalledatxlastupdatedatx'.\OC_Util::getChannel().'x'.\OC_Util::getEditionString().'x';
+ }
+
+ /**
+ * @return array
+ */
+ public function versionCompatibilityTestData() {
+ return [
+ ['1.0.0.0', '2.2.0', true],
+ ['1.1.1.1', '2.0.0', true],
+ ['5.0.3', '4.0.3', false],
+ ['12.0.3', '13.4.5', true],
+ ['1', '2', true],
+ ['2', '2', true],
+ ['6.0.5', '6.0.6', true],
+ ['5.0.6', '7.0.4', false],
+ ];
+ }
+
+ public function testSetSimulateStepEnabled() {
+ $this->updater->setSimulateStepEnabled(true);
+ $this->assertSame(true, $this->invokePrivate($this->updater, 'simulateStepEnabled'));
+ $this->updater->setSimulateStepEnabled(false);
+ $this->assertSame(false, $this->invokePrivate($this->updater, 'simulateStepEnabled'));
+ }
+
+ public function testSetUpdateStepEnabled() {
+ $this->updater->setUpdateStepEnabled(true);
+ $this->assertSame(true, $this->invokePrivate($this->updater, 'updateStepEnabled'));
+ $this->updater->setUpdateStepEnabled(false);
+ $this->assertSame(false, $this->invokePrivate($this->updater, 'updateStepEnabled'));
+ }
+
+ public function testSetSkip3rdPartyAppsDisable() {
+ $this->updater->setSkip3rdPartyAppsDisable(true);
+ $this->assertSame(true, $this->invokePrivate($this->updater, 'skip3rdPartyAppsDisable'));
+ $this->updater->setSkip3rdPartyAppsDisable(false);
+ $this->assertSame(false, $this->invokePrivate($this->updater, 'skip3rdPartyAppsDisable'));
+ }
+
+ /**
* @dataProvider versionCompatibilityTestData
+ *
+ * @param string $oldVersion
+ * @param string $newVersion
+ * @param bool $result
*/
public function testIsUpgradePossible($oldVersion, $newVersion, $result) {
- $updater = new Updater(\OC::$server->getHTTPHelper(), \OC::$server->getConfig());
+ $updater = new Updater($this->httpHelper, $this->config);
$this->assertSame($result, $updater->isUpgradePossible($oldVersion, $newVersion));
}
- public function testBrokenXmlResponse(){
- $invalidUpdater = $this->getUpdaterMock('OMG!');
- $invalidResult = $invalidUpdater->check();
- $this->assertEmpty($invalidResult);
+ public function testCheckInCache() {
+ $expectedResult = [
+ 'version' => '8.0.4.2',
+ 'versionstring' => 'ownCloud 8.0.4',
+ 'url' => 'https://download.owncloud.org/community/owncloud-8.0.4.zip',
+ 'web' => 'http://doc.owncloud.org/server/8.0/admin_manual/maintenance/upgrade.html',
+ ];
+
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue(time()));
+ $this->config
+ ->expects($this->at(1))
+ ->method('getAppValue')
+ ->with('core', 'lastupdateResult')
+ ->will($this->returnValue(json_encode($expectedResult)));
+
+ $this->assertSame($expectedResult, $this->updater->check());
}
- public function testEmptyResponse(){
- $emptyUpdater = $this->getUpdaterMock('');
- $emptyResult = $emptyUpdater->check();
- $this->assertEmpty($emptyResult);
+ public function testCheckWithoutUpdateUrl() {
+ $expectedResult = [
+ 'version' => '8.0.4.2',
+ 'versionstring' => 'ownCloud 8.0.4',
+ 'url' => 'https://download.owncloud.org/community/owncloud-8.0.4.zip',
+ 'web' => 'http://doc.owncloud.org/server/8.0/admin_manual/maintenance/upgrade.html',
+ ];
+
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue(0));
+ $this->config
+ ->expects($this->at(1))
+ ->method('setAppValue')
+ ->with('core', 'lastupdatedat', time());
+ $this->config
+ ->expects($this->at(3))
+ ->method('getAppValue')
+ ->with('core', 'installedat')
+ ->will($this->returnValue('installedat'));
+ $this->config
+ ->expects($this->at(4))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue('lastupdatedat'));
+ $this->config
+ ->expects($this->at(5))
+ ->method('setAppValue')
+ ->with('core', 'lastupdateResult', json_encode($expectedResult));
+
+ $updateXml = '<?xml version="1.0"?>
+<owncloud>
+ <version>8.0.4.2</version>
+ <versionstring>ownCloud 8.0.4</versionstring>
+ <url>https://download.owncloud.org/community/owncloud-8.0.4.zip</url>
+ <web>http://doc.owncloud.org/server/8.0/admin_manual/maintenance/upgrade.html</web>
+</owncloud>';
+ $this->httpHelper
+ ->expects($this->once())
+ ->method('getUrlContent')
+ ->with($this->buildUpdateUrl('https://updates.owncloud.com/server/'))
+ ->will($this->returnValue($updateXml));
- // Error while fetching new contents e.g. too many redirects
- $falseUpdater = $this->getUpdaterMock(false);
- $falseResult = $falseUpdater->check();
- $this->assertEmpty($falseResult);
+ $this->assertSame($expectedResult, $this->updater->check());
}
- public function testValidEmptyXmlResponse(){
- $updater = $this->getUpdaterMock(
- '<?xml version="1.0"?><owncloud><version></version><versionstring></versionstring><url></url><web></web></owncloud>'
- );
- $result = array_map('strval', $updater->check());
-
- $this->assertArrayHasKey('version', $result);
- $this->assertArrayHasKey('versionstring', $result);
- $this->assertArrayHasKey('url', $result);
- $this->assertArrayHasKey('web', $result);
- $this->assertEmpty($result['version']);
- $this->assertEmpty($result['versionstring']);
- $this->assertEmpty($result['url']);
- $this->assertEmpty($result['web']);
+ public function testCheckWithInvalidXml() {
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue(0));
+ $this->config
+ ->expects($this->at(1))
+ ->method('setAppValue')
+ ->with('core', 'lastupdatedat', time());
+ $this->config
+ ->expects($this->at(3))
+ ->method('getAppValue')
+ ->with('core', 'installedat')
+ ->will($this->returnValue('installedat'));
+ $this->config
+ ->expects($this->at(4))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue('lastupdatedat'));
+ $this->config
+ ->expects($this->at(5))
+ ->method('setAppValue')
+ ->with('core', 'lastupdateResult', 'false');
+
+ $updateXml = 'Invalid XML Response!';
+ $this->httpHelper
+ ->expects($this->once())
+ ->method('getUrlContent')
+ ->with($this->buildUpdateUrl('https://updates.owncloud.com/server/'))
+ ->will($this->returnValue($updateXml));
+
+ $this->assertSame([], $this->updater->check());
}
- public function testValidUpdateResponse(){
- $newUpdater = $this->getUpdaterMock(
- '<?xml version="1.0"?>
+ public function testCheckWithUpdateUrl() {
+ $expectedResult = [
+ 'version' => '8.0.4.2',
+ 'versionstring' => 'ownCloud 8.0.4',
+ 'url' => 'https://download.owncloud.org/community/owncloud-8.0.4.zip',
+ 'web' => 'http://doc.owncloud.org/server/8.0/admin_manual/maintenance/upgrade.html',
+ ];
+
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue(0));
+ $this->config
+ ->expects($this->at(1))
+ ->method('setAppValue')
+ ->with('core', 'lastupdatedat', time());
+ $this->config
+ ->expects($this->at(3))
+ ->method('getAppValue')
+ ->with('core', 'installedat')
+ ->will($this->returnValue('installedat'));
+ $this->config
+ ->expects($this->at(4))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue('lastupdatedat'));
+ $this->config
+ ->expects($this->at(5))
+ ->method('setAppValue')
+ ->with('core', 'lastupdateResult', json_encode($expectedResult));
+
+ $updateXml = '<?xml version="1.0"?>
<owncloud>
- <version>7.0.3.4</version>
- <versionstring>ownCloud 7.0.3</versionstring>
- <url>http://download.owncloud.org/community/owncloud-7.0.3.zip</url>
- <web>http://owncloud.org/</web>
-</owncloud>'
- );
- $newResult = array_map('strval', $newUpdater->check());
-
- $this->assertArrayHasKey('version', $newResult);
- $this->assertArrayHasKey('versionstring', $newResult);
- $this->assertArrayHasKey('url', $newResult);
- $this->assertArrayHasKey('web', $newResult);
- $this->assertEquals('7.0.3.4', $newResult['version']);
- $this->assertEquals('ownCloud 7.0.3', $newResult['versionstring']);
- $this->assertEquals('http://download.owncloud.org/community/owncloud-7.0.3.zip', $newResult['url']);
- $this->assertEquals('http://owncloud.org/', $newResult['web']);
+ <version>8.0.4.2</version>
+ <versionstring>ownCloud 8.0.4</versionstring>
+ <url>https://download.owncloud.org/community/owncloud-8.0.4.zip</url>
+ <web>http://doc.owncloud.org/server/8.0/admin_manual/maintenance/upgrade.html</web>
+</owncloud>';
+ $this->httpHelper
+ ->expects($this->once())
+ ->method('getUrlContent')
+ ->with($this->buildUpdateUrl('https://myupdater.com/'))
+ ->will($this->returnValue($updateXml));
+
+ $this->assertSame($expectedResult, $this->updater->check('https://myupdater.com/'));
}
- protected function getUpdaterMock($content){
- // Invalidate cache
- $mockedConfig = $this->getMockBuilder('\OCP\IConfig')
- ->disableOriginalConstructor()
- ->getMock()
- ;
+ public function testCheckWithEmptyValidXmlResponse() {
+ $expectedResult = [
+ 'version' => '',
+ 'versionstring' => '',
+ 'url' => '',
+ 'web' => '',
+ ];
- $clientService = $this->getMock('\OCP\Http\Client\IClientService');
- $mockedHTTPHelper = $this->getMockBuilder('\OC\HTTPHelper')
- ->setConstructorArgs([\OC::$server->getConfig(), $clientService])
- ->getMock()
- ;
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue(0));
+ $this->config
+ ->expects($this->at(1))
+ ->method('setAppValue')
+ ->with('core', 'lastupdatedat', time());
+ $this->config
+ ->expects($this->at(3))
+ ->method('getAppValue')
+ ->with('core', 'installedat')
+ ->will($this->returnValue('installedat'));
+ $this->config
+ ->expects($this->at(4))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue('lastupdatedat'));
- $mockedHTTPHelper->expects($this->once())->method('getUrlContent')->will($this->returnValue($content));
+ $updateXml = '<?xml version="1.0"?>
+<owncloud>
+ <version></version>
+ <versionstring></versionstring>
+ <url></url>
+ <web></web>
+</owncloud>';
+ $this->httpHelper
+ ->expects($this->once())
+ ->method('getUrlContent')
+ ->with($this->buildUpdateUrl('https://updates.owncloud.com/server/'))
+ ->will($this->returnValue($updateXml));
- return new Updater($mockedHTTPHelper, $mockedConfig);
+ $this->assertSame($expectedResult, $this->updater->check());
}
+ public function testCheckWithEmptyInvalidXmlResponse() {
+ $expectedResult = [];
+
+ $this->config
+ ->expects($this->at(0))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue(0));
+ $this->config
+ ->expects($this->at(1))
+ ->method('setAppValue')
+ ->with('core', 'lastupdatedat', time());
+ $this->config
+ ->expects($this->at(3))
+ ->method('getAppValue')
+ ->with('core', 'installedat')
+ ->will($this->returnValue('installedat'));
+ $this->config
+ ->expects($this->at(4))
+ ->method('getAppValue')
+ ->with('core', 'lastupdatedat')
+ ->will($this->returnValue('lastupdatedat'));
+ $this->config
+ ->expects($this->at(5))
+ ->method('setAppValue')
+ ->with('core', 'lastupdateResult', json_encode($expectedResult));
+
+ $updateXml = '';
+ $this->httpHelper
+ ->expects($this->once())
+ ->method('getUrlContent')
+ ->with($this->buildUpdateUrl('https://updates.owncloud.com/server/'))
+ ->will($this->returnValue($updateXml));
+
+ $this->assertSame($expectedResult, $this->updater->check());
+ }
}