From c72fa101ed2fefe73952a8dc13617ed1bcd038be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20Mo=C3=9Fhammer?= Date: Thu, 20 Jun 2013 17:01:13 +0200 Subject: [PATCH] Add clearstatcache and tests for ModuleManager Added the clearstatcache call before enabling or disabling modules, as this prevents a 'File exists' error that occurs sometimes on symlink creation (even when the folder is empty). Also added tests for teh moduleManager refs #4092 --- .../Icinga/Application/Modules/Manager.php | 76 +++++++----- .../Icinga/Application/Modules/Manager.php | 111 ++++++++++++++++++ 2 files changed, 157 insertions(+), 30 deletions(-) create mode 100644 test/php/library/Icinga/Application/Modules/Manager.php diff --git a/library/Icinga/Application/Modules/Manager.php b/library/Icinga/Application/Modules/Manager.php index 4061a2421..f4612de7f 100644 --- a/library/Icinga/Application/Modules/Manager.php +++ b/library/Icinga/Application/Modules/Manager.php @@ -2,33 +2,39 @@ namespace Icinga\Application\Modules; -use Icinga\Application\ApplicationBootstrap; -use Icinga\Data\ArrayDatasource; -use Icinga\Web\Notification; use Icinga\Exception\ConfigurationError; use Icinga\Exception\SystemPermissionException; +use Icinga\Exception\ProgrammingError; // TODO: show whether enabling/disabling modules is allowed by checking enableDir // perms class Manager { - protected $installedBaseDirs; + protected $installedBaseDirs = null; protected $enabledDirs = array(); protected $loadedModules = array(); protected $index; protected $app; - protected $enableDir; - - public function __construct(ApplicationBootstrap $app, $dir = null) + protected $modulePaths = array(); + /** + * @param $app : The applicaiton bootstrap. This one needs a properly defined interface + * In order to test it correctly, the application now only requires a stdClass + * @param $dir : + **/ + public function __construct($app, $enabledDir = null, array $availableDirs = array()) { $this->app = $app; - if ($dir === null) { - $dir = $this->app->getConfig()->getConfigDir() + if (empty($availableDirs)) { + $availableDirs = array(ICINGA_APPDIR."/../modules"); + } + $this->modulePaths = $availableDirs; + if ($enabledDir === null) { + $enabledDir = $this->app->getConfig()->getConfigDir() . '/enabledModules'; } - $this->prepareEssentials($dir); + $this->prepareEssentials($enabledDir); $this->detectEnabledModules(); } @@ -46,10 +52,17 @@ class Manager } } + public function select() + { + $source = new \Icinga\Data\ArrayDataSource($this->getModuleInfo()); + return $source->select(); + } + protected function detectEnabledModules() { $fh = opendir($this->enableDir); + $this->enabledDirs = array(); while (false !== ($file = readdir($fh))) { if ($file[0] === '.') { @@ -78,12 +91,18 @@ class Manager return $this; } - public function loadModule($name) + public function loadModule($name, $moduleBase = null) { if ($this->hasLoaded($name)) { return $this; } - $module = new Module($this->app, $name, $this->getModuleDir($name)); + + $module = null; + if ($moduleBase === null) { + $module = new Module($this->app, $name, $this->getModuleDir($name)); + } else { + $module = new $moduleBase($this->app, $name, $this->getModuleDir($name)); + } $module->register(); $this->loadedModules[$name] = $module; return $this; @@ -100,6 +119,7 @@ class Manager ); return $this; } + clearstatcache(true); $target = $this->installedBaseDirs[$name]; $link = $this->enableDir . '/' . $name; if (! is_writable($this->enableDir)) { @@ -118,6 +138,7 @@ class Manager throw new SystemPermissionException($error["message"], "symlink", $link); } } + $this->enabledDirs[$name] = $link; return $this; } @@ -151,6 +172,7 @@ class Manager } else { } + unset($this->enabledDirs[$name]); return $this; } @@ -228,12 +250,6 @@ class Manager return $info; } - public function select() - { - $ds = new ArrayDatasource($this->getModuleInfo()); - return $ds->select(); - } - public function listEnabledModules() { return array_keys($this->enabledDirs); @@ -254,19 +270,19 @@ class Manager public function detectInstalledModules() { - // TODO: Allow multiple paths for installed modules (e.g. web vs pkg) - $basedir = realpath(ICINGA_APPDIR . '/../modules'); - $fh = @opendir($basedir); - if ($fh === false) { - return $this; - } - - while ($name = readdir($fh)) { - if ($name[0] === '.') { - continue; + foreach ($this->modulePaths as $basedir) { + $fh = opendir($basedir); + if ($fh === false) { + return $this; } - if (is_dir($basedir . '/' . $name)) { - $this->installedBaseDirs[$name] = $basedir . '/' . $name; + + while ($name = readdir($fh)) { + if ($name[0] === '.') { + continue; + } + if (is_dir($basedir . '/' . $name)) { + $this->installedBaseDirs[$name] = $basedir . '/' . $name; + } } } } diff --git a/test/php/library/Icinga/Application/Modules/Manager.php b/test/php/library/Icinga/Application/Modules/Manager.php new file mode 100644 index 000000000..24d2a8c25 --- /dev/null +++ b/test/php/library/Icinga/Application/Modules/Manager.php @@ -0,0 +1,111 @@ +name = $name; + $this->dir = $dir; + } + + public function register() + { + } +} + + +class ManagerTest extends \PHPUnit_Framework_TestCase +{ + const MODULE_TARGET = "/tmp"; + + protected function setUp() + { + $moduleDir = self::MODULE_TARGET; + if (!is_writable($moduleDir)) { + $this->markTestSkipped("Temporary folder not writable for this user"); + return; + } + if (is_dir($moduleDir."/enabledModules")) { + exec("rm -r $moduleDir/enabledModules"); + } + + mkdir($moduleDir."/enabledModules"); + } + + public function testDetectEnabledModules() + { + $manager = new ModuleManager(null, "/tmp/enabledModules", array("none")); + $this->assertEmpty($manager->listEnabledModules()); + + symlink(getcwd()."/res/testModules/module1", "/tmp/enabledModules/module1"); + $manager = new ModuleManager(null, "/tmp/enabledModules", array("none")); + $this->assertEquals(array("module1"), $manager->listEnabledModules()); + symlink(getcwd()."/res/testModules/module2", "/tmp/enabledModules/module2"); + symlink(getcwd()."/res/???", "/tmp/enabledModules/module3"); + $manager = new ModuleManager(null, "/tmp/enabledModules", array("none")); + $this->assertEquals(array("module1", "module2"), $manager->listEnabledModules()); + } + + public function testLoadModule() + { + $manager = new ModuleManager(null, "/tmp/enabledModules", array("./res/testModules")); + $this->assertEmpty($manager->getLoadedModules()); + $manager->loadModule("module1", "Tests\Icinga\Application\Module\Manager\ModuleMock"); + $elems = $manager->getLoadedModules(); + $this->assertNotEmpty($elems); + $this->assertTrue(isset($elems["module1"])); + // assert the changes not to be permanent: + $manager = new ModuleManager(null, "/tmp/enabledModules", array("./res/testModules")); + $this->assertEmpty($manager->getLoadedModules()); + } + + public function testEnableModule() + { + $manager = new ModuleManager(null, "/tmp/enabledModules", array(getcwd()."/res/testModules")); + $this->assertEmpty($manager->listEnabledModules()); + $manager->enableModule("module1"); + $elems = $manager->listEnabledModules(); + $this->assertNotEmpty($elems); + $this->assertEquals($elems[0], "module1"); + $this->assertTrue(is_link("/tmp/enabledModules/module1")); + // assert the changes to be permanent: + $manager = new ModuleManager(null, "/tmp/enabledModules", array("./res/testModules")); + $this->assertNotEmpty($manager->listEnabledModules()); + } + + public function testDisableModule() + { + clearstatcache(true); + symlink(getcwd()."/res/testModules/module1", "/tmp/enabledModules/module1"); + $manager = new ModuleManager(null, "/tmp/enabledModules", array(getcwd()."/res/testModules")); + $elems = $manager->listEnabledModules(); + $this->assertNotEmpty($elems); + $this->assertEquals($elems[0], "module1"); + $manager->disableModule("module1"); + $this->assertFalse(file_exists("/tmp/enabledModules/module1")); + $this->assertEmpty($manager->listEnabledModules()); + // assert the changes to be permanent: + $manager = new ModuleManager(null, "/tmp/enabledModules", array("./res/testModules")); + $this->assertEmpty($manager->listEnabledModules()); + } + + protected function tearDown() + { + $moduleDir = self::MODULE_TARGET; + exec("rm -r $moduleDir/enabledModules"); + + } +}