From b469e9f6fb83758ad91b8e41d81319ab3a73f098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 1 Dec 2014 21:47:22 +0100 Subject: [PATCH] introduce dependency analyzer to take care of app dependencies some more unit tests on xml info parser --- lib/private/app/dependencyanalyzer.php | 58 ++++++++++++++ lib/private/app/infoparser.php | 6 +- lib/private/app/platform.php | 17 ++++ settings/controller/appsettingscontroller.php | 10 ++- tests/data/app/strange-types-info.json | 24 ++++++ tests/data/app/strange-types-info.xml | 23 ++++++ tests/lib/app/dependencyanalyzer.php | 77 +++++++++++++++++++ tests/lib/app/infoparser.php | 21 +++-- 8 files changed, 227 insertions(+), 9 deletions(-) create mode 100644 lib/private/app/dependencyanalyzer.php create mode 100644 lib/private/app/platform.php create mode 100644 tests/data/app/strange-types-info.json create mode 100644 tests/data/app/strange-types-info.xml create mode 100644 tests/lib/app/dependencyanalyzer.php diff --git a/lib/private/app/dependencyanalyzer.php b/lib/private/app/dependencyanalyzer.php new file mode 100644 index 0000000000..c76181926e --- /dev/null +++ b/lib/private/app/dependencyanalyzer.php @@ -0,0 +1,58 @@ +system = $system; + $this->l = $l; + $this->missing = array(); + $this->dependencies = array(); + if (array_key_exists('dependencies', $app)) { + $this->dependencies = $app['dependencies']; + } + } + + /** + * @param array $app + * @returns array of missing dependencies + */ + public function analyze() { + $this->analysePhpVersion(); + return $this->missing; + } + + private function analysePhpVersion() { + if (!array_key_exists('php', $this->dependencies)) { + return; + } + + if (array_key_exists('min-version', $this->dependencies['php'])) { + $minVersion = $this->dependencies['php']['min-version']; + if (version_compare($this->system->getPhpVersion(), $minVersion, '<')) { + $this->missing[] = (string)$this->l->t('PHP %s or higher is required.', $minVersion); + } + } + if (array_key_exists('max-version', $this->dependencies['php'])) { + $maxVersion = $this->dependencies['php']['max-version']; + if (version_compare($this->system->getPhpVersion(), $maxVersion, '>')) { + $this->missing[] = (string)$this->l->t('PHP with a version less then %s is required.', $maxVersion); + } + } + } + +} diff --git a/lib/private/app/infoparser.php b/lib/private/app/infoparser.php index b0327fa4fd..e220fb40df 100644 --- a/lib/private/app/infoparser.php +++ b/lib/private/app/infoparser.php @@ -64,7 +64,7 @@ class InfoParser { $array['types'] = array(); } - if (array_key_exists('documentation', $array)) { + if (array_key_exists('documentation', $array) && is_array($array['documentation'])) { foreach ($array['documentation'] as $key => $url) { // If it is not an absolute URL we assume it is a key // i.e. admin-ldap will get converted to go.php?to=admin-ldap @@ -78,7 +78,9 @@ class InfoParser { if (array_key_exists('types', $array)) { foreach ($array['types'] as $type => $v) { unset($array['types'][$type]); - $array['types'][] = $type; + if (is_string($type)) { + $array['types'][] = $type; + } } } diff --git a/lib/private/app/platform.php b/lib/private/app/platform.php new file mode 100644 index 0000000000..292159337a --- /dev/null +++ b/lib/private/app/platform.php @@ -0,0 +1,17 @@ +l10n); + $missing = $dependencyAnalyzer->analyze(); + + $app['canInstall'] = empty($missing); + $app['missingDependencies'] = $missing; return $app; }, $apps); return array('apps' => $apps, 'status' => 'success'); } - } diff --git a/tests/data/app/strange-types-info.json b/tests/data/app/strange-types-info.json new file mode 100644 index 0000000000..eedf8bd051 --- /dev/null +++ b/tests/data/app/strange-types-info.json @@ -0,0 +1,24 @@ +{ + "info": [], + "remote": [], + "public": [], + "id": "files_encryption", + "name": "Server-side Encryption", + "description": "\n\tThis application encrypts all files accessed by ownCloud at rest, wherever they are stored. As an example, with this application enabled, external cloud based Amazon S3 storage will be encrypted, protecting this data on storage outside of the control of the Admin. When this application is enabled for the first time, all files are encrypted as users log in and are prompted for their password. The recommended recovery key option enables recovery of files in case the key is lost. \n\tNote that this app encrypts all files that are touched by ownCloud, so external storage providers and applications such as SharePoint will see new files encrypted when they are accessed. Encryption is based on AES 128 or 256 bit keys. More information is available in the Encryption documentation \n\t", + "licence": "AGPL", + "author": "Sam Tuke, Bjoern Schiessle, Florin Peter", + "requiremin": "4", + "shipped": "true", + "documentation": { + "user": "https://docs.example.com/server/go.php?to=user-encryption", + "admin": "https://docs.example.com/server/go.php?to=admin-encryption" + }, + "rememberlogin": "false", + "types": [], + "ocsid": "166047", + "dependencies": { + "php": { + "min-version": 5.4 + } + } +} diff --git a/tests/data/app/strange-types-info.xml b/tests/data/app/strange-types-info.xml new file mode 100644 index 0000000000..e7e8f0d028 --- /dev/null +++ b/tests/data/app/strange-types-info.xml @@ -0,0 +1,23 @@ + + + files_encryption + Server-side Encryption + + This application encrypts all files accessed by ownCloud at rest, wherever they are stored. As an example, with this application enabled, external cloud based Amazon S3 storage will be encrypted, protecting this data on storage outside of the control of the Admin. When this application is enabled for the first time, all files are encrypted as users log in and are prompted for their password. The recommended recovery key option enables recovery of files in case the key is lost. + Note that this app encrypts all files that are touched by ownCloud, so external storage providers and applications such as SharePoint will see new files encrypted when they are accessed. Encryption is based on AES 128 or 256 bit keys. More information is available in the Encryption documentation + + AGPL + Sam Tuke, Bjoern Schiessle, Florin Peter + 4 + true + + user-encryption + admin-encryption + + false + + 166047 + + 5.4 + + diff --git a/tests/lib/app/dependencyanalyzer.php b/tests/lib/app/dependencyanalyzer.php new file mode 100644 index 0000000000..d0c2919f47 --- /dev/null +++ b/tests/lib/app/dependencyanalyzer.php @@ -0,0 +1,77 @@ +platformMock = $this->getMockBuilder('\OC\App\Platform') + ->getMock(); + $this->platformMock->expects($this->any()) + ->method('getPhpVersion') + ->will( $this->returnValue('5.4.3')); + $this->l10nMock = $this->getMockBuilder('\OCP\IL10N') + ->disableOriginalConstructor() + ->getMock(); + $this->l10nMock->expects($this->any()) + ->method('t') + ->will($this->returnCallback(function($text, $parameters = array()) { + return vsprintf($text, $parameters); + })); + } + + /** + * @dataProvider providesPhpVersion + */ + public function testPhpVersion($expectedMissing, $minVersion, $maxVersion) { + $app = array( + 'dependencies' => array( + 'php' => array() + ) + ); + if (!is_null($minVersion)) { + $app['dependencies']['php']['min-version'] = $minVersion; + } + if (!is_null($maxVersion)) { + $app['dependencies']['php']['max-version'] = $maxVersion; + } + $analyser = new \OC\App\DependencyAnalyzer($app, $this->platformMock, $this->l10nMock); + $missing = $analyser->analyze(); + + $this->assertTrue(is_array($missing)); + $this->assertEquals(count($expectedMissing), count($missing)); + $this->assertEquals($expectedMissing, $missing); + } + + function providesPhpVersion() { + return array( + array(array(), null, null), + array(array(), '5.4', null), + array(array(), null, '5.5'), + array(array(), '5.4', '5.5'), + array(array('PHP 5.4.4 or higher is required.'), '5.4.4', null), + array(array('PHP with a version less then 5.4.2 is required.'), null, '5.4.2'), + ); + } +} diff --git a/tests/lib/app/infoparser.php b/tests/lib/app/infoparser.php index 277e1582e4..20668c0508 100644 --- a/tests/lib/app/infoparser.php +++ b/tests/lib/app/infoparser.php @@ -39,15 +39,24 @@ class InfoParser extends \PHPUnit_Framework_TestCase { $this->parser = new \OC\App\InfoParser($httpHelper, $urlGenerator); } - public function testParsingValidXml() { - $expectedData = json_decode(file_get_contents(OC::$SERVERROOT.'/tests/data/app/expected-info.json'), true); - $data = $this->parser->parse(OC::$SERVERROOT.'/tests/data/app/valid-info.xml'); + /** + * @dataProvider providesInfoXml + */ + public function testParsingValidXml($expectedJson, $xmlFile) { + $expectedData = null; + if (!is_null($expectedJson)) { + $expectedData = json_decode(file_get_contents(OC::$SERVERROOT . "/tests/data/app/$expectedJson"), true); + } + $data = $this->parser->parse(OC::$SERVERROOT. "/tests/data/app/$xmlFile"); $this->assertEquals($expectedData, $data); } - public function testParsingInvalidXml() { - $data = $this->parser->parse(OC::$SERVERROOT.'/tests/data/app/invalid-info.xml'); - $this->assertNull($data); + function providesInfoXml() { + return array( + array('expected-info.json', 'valid-info.xml'), + array('strange-types-info.json', 'strange-types-info.xml'), + array(null, 'invalid-info.xml'), + ); } }