Rewrite test for Icinga\Web\Hook

refs #6011
This commit is contained in:
Johannes Meyer 2014-04-24 14:40:49 +02:00
parent 2b15d35dec
commit 290fe9eeb5
7 changed files with 205 additions and 172 deletions

View File

@ -29,9 +29,9 @@
namespace Icinga\Web;
use Exception;
use Icinga\Logger\Logger;
use Icinga\Exception\ProgrammingError;
use stdClass;
/**
* Icinga Web Hook registry
@ -79,9 +79,9 @@ class Hook
/**
* Whether someone registered itself for the given hook name
*
* @param string $name One of the predefined hook names
* @param string $name One of the predefined hook names
*
* @return bool
* @return bool
*/
public static function has($name)
{
@ -89,72 +89,29 @@ class Hook
}
/**
* Get the first registered instance for the given hook name
* Create or return an instance of a given hook
*
* TODO: Multiple instances are not handled yet
* TODO: Should return some kind of a hook interface
*
* @param string $name One of the predefined hook names
*
* @return mixed
* @throws ProgrammingError
*/
public static function get($name)
{
if (! self::has($name)) {
return null;
}
if (! array_key_exists($name, self::$instances)) {
$class = self::$hooks[$name];
try {
$obj = new $class();
} catch (\Exception $e) {
// TODO: Persist unloading for "some time" or "current session"
Logger::debug(
'Hook "%s" (%s) failed, will be unloaded: %s',
$name,
$class,
$e->getMessage()
);
unset(self::$hooks[$name]);
return null;
}
$base_class = 'Icinga\\Web\\Hook\\' . ucfirst($name);
if (! $obj instanceof $base_class) {
throw new ProgrammingError(
sprintf(
'%s is not an instance of %s',
get_class($obj),
$base_class
)
);
}
self::$instances[$name] = $obj;
}
return self::$instances[$name];
}
/**
* Create or return an instance of the hook
*
* @param string $name
* @param string $key
* @return stdClass
* @param string $name One of the predefined hook names
* @param string $key The identifier of a specific subtype
*
* @return mixed
*/
public static function createInstance($name, $key)
{
if (!self::has($name, $key)) {
return null;
}
if (isset(self::$instances[$name][$key])) {
return self::$instances[$name][$key];
}
$class = self::$hooks[$name][$key];
try {
$instance = new $class();
} catch (\Exception $e) {
} catch (Exception $e) {
Logger::debug(
'Hook "%s" (%s) (%s) failed, will be unloaded: %s',
$name,
@ -162,9 +119,11 @@ class Hook
$class,
$e->getMessage()
);
// TODO: Persist unloading for "some time" or "current session"
unset(self::$hooks[$name][$key]);
return null;
}
self::assertValidHook($instance, $name);
self::$instances[$name][$key] = $instance;
return $instance;
@ -173,11 +132,12 @@ class Hook
/**
* Test for a valid class name
*
* @param stdClass $instance
* @param string $name
* @throws ProgrammingError
* @param mixed $instance
* @param string $name
*
* @throws ProgrammingError
*/
private static function assertValidHook(&$instance, $name)
private static function assertValidHook($instance, $name)
{
$base_class = self::$BASE_NS . ucfirst($name);
if (!$instance instanceof $base_class) {
@ -194,43 +154,45 @@ class Hook
/**
* Return all instances of a specific name
*
* @param string $name
* @param string $name One of the predefined hook names
*
* @return array
* @return array
*/
public static function all($name)
{
if (!self::has($name)) {
return array();
}
foreach (self::$hooks[$name] as $key => $hook) {
if (self::createInstance($name, $key) === null) {
return array();
}
}
return self::$instances[$name];
}
/**
* Get the first hook
*
* @param string $name
* @param string $name One of the predefined hook names
*
* @return stdClass
* @return null|mixed
*/
public static function first($name)
{
return self::createInstance($name, key(self::$hooks[$name]));
if (self::has($name)) {
return self::createInstance($name, key(self::$hooks[$name]));
}
}
/**
* Register your hook
*
* @param string $name One of the predefined hook names
* @param string $key
* @param string $class Your class name, must inherit one of the classes
* in the Icinga/Web/Hook folder
* Alias for Hook::registerClass()
*
* @see Hook::registerClass()
*/
public static function register($name, $key, $class)
{
@ -240,12 +202,17 @@ class Hook
/**
* Register a class
*
* @param string $name
* @param string $key
* @param string $class
* @param string $name One of the predefined hook names
* @param string $key The identifier of a specific subtype
* @param string $class Your class name, must inherit one of the
* classes in the Icinga/Web/Hook folder
*/
public static function registerClass($name, $key, $class)
{
if (!class_exists($class)) {
throw new ProgrammingError('"' . $class . '" is not an existing class');
}
if (!isset(self::$hooks[$name])) {
self::$hooks[$name] = array();
}
@ -256,23 +223,23 @@ class Hook
/**
* Register an object
*
* @param string $name
* @param string $key
* @param object $object
* @param string $name One of the predefined hook names
* @param string $key The identifier of a specific subtype
* @param object $object The instantiated hook to register
*
* @throws ProgrammingError
* @throws ProgrammingError
*/
public static function registerObject($name, $key, $object)
{
if (!is_object($object)) {
throw new ProgrammingError('object is not an instantiated class');
throw new ProgrammingError('"' . $object . '" is not an instantiated class');
}
if (!isset(self::$instances[$name])) {
self::$instances[$name] = array();
}
self::$instances[$name][$key] =& $object;
self::$instances[$name][$key] = $object;
self::registerClass($name, $key, get_class($object));
}
}

View File

@ -90,7 +90,7 @@ class ConfigurationTabBuilder
{
/** @var ConfigurationTab $configTab */
$configTab = null;
foreach (Hook::get(self::HOOK_NAMESPACE) as $configTab) {
foreach (Hook::all(self::HOOK_NAMESPACE) as $configTab) {
if (!$configTab instanceof ConfigurationTabInterface) {
throw new ProgrammingError('tab not instance of ConfigTabInterface');
}

View File

@ -110,7 +110,6 @@ EOT;
$query = $form->getElement('query')->setDecorators(array('ViewHelper'));
$badges = new FilterBadgeRenderer($this->initialFilter);
$form->setIgnoreChangeDiscarding(true);
return '<div class="pull-right">' . $badges->render($view) . '</div>' . $form;
$html = str_replace('{{FORM}}', $form->render($view), self::$TPL);
$html = '<div class="input-append">' . $html . '</div>';

View File

@ -74,7 +74,7 @@ class Monitoring_ListController extends Controller
public function init()
{
$this->backend = Backend::createBackend($this->_getParam('backend'));
$this->view->grapher = Hook::get('grapher');
$this->view->grapher = Hook::first('grapher');
$this->createTabs();
$this->view->activeRowHref = $this->getParam('detail');
$this->view->compact = ($this->_request->getParam('view') === 'compact');

View File

@ -56,7 +56,6 @@ class Zend_View_Helper_CommandForm extends Zend_View_Helper_Abstract
{
$form = new Form();
$form->setAttrib('class', 'inline');
$form->setIgnoreChangeDiscarding(true);
$form->setRequest(Zend_Controller_Front::getInstance()->getRequest());
// Filter work only from get parts. Put important

View File

@ -37,12 +37,12 @@ class Environment
public static function grapher($env = null)
{
return Hook::get('grapher', null, self::config($env, 'grapher'));
return Hook::createInstance('grapher', null, self::config($env, 'grapher'));
}
public static function configBackend($env = null)
{
return Hook::get(
return Hook::createInstance(
'configBackend',
null,
self::config($env, 'configBackend')

View File

@ -4,27 +4,16 @@
namespace Tests\Icinga\Web;
use \Mockery;
use Mockery;
use Exception;
use Icinga\Web\Hook;
use Icinga\Test\BaseTestCase;
class Base
{
}
class TestHookImplementation extends Base
{
}
class TestBadHookImplementation
{
}
class ErrorProneHookImplementation
{
public function __construct()
{
throw new \Exception("HOOK ERROR");
throw new Exception();
}
}
@ -42,103 +31,182 @@ class HookTest extends BaseTestCase
Hook::clean();
}
public function testHas()
public function testWhetherHasReturnsTrueIfGivenAKnownHook()
{
$this->assertFalse(Hook::has("a"));
$this->assertFalse(Hook::has("a","b"));
Hook::registerClass('TestHook', __FUNCTION__, get_class(Mockery::mock(Hook::$BASE_NS . 'TestHook')));
Hook::registerClass("a","b","c");
$this->assertTrue(Hook::has("a"));
$this->assertTrue(Hook::has("a","b"));
$this->assertTrue(Hook::has('TestHook'), 'Hook::has does not return true if given a known hook');
}
public function testCreateInstance()
public function testWhetherHasReturnsFalseIfGivenAnUnknownHook()
{
Hook::$BASE_NS = "Tests\\Icinga\\Web\\";
Hook::registerClass("Base","b","Tests\\Icinga\\Web\\TestHookImplementation");
$this->assertInstanceOf("Tests\\Icinga\\Web\\TestHookImplementation",Hook::createInstance("Base","b"));
Hook::clean();
$this->assertFalse(Hook::has('not_existing'), 'Hook::has does not return false if given an unknown hook');
}
public function testCreateInvalidInstance1()
public function testWhetherHooksCanBeRegisteredWithRegisterClass()
{
$this->setExpectedException('\Icinga\Exception\ProgrammingError');
Hook::$BASE_NS = "Tests\\Icinga\\Web\\";
Hook::registerClass("Base","b","Tests\\Icinga\\Web\\TestBadHookImplementation");
Hook::createInstance("Base","b");
Hook::clean();
Hook::registerClass('TestHook', __FUNCTION__, get_class(Mockery::mock(Hook::$BASE_NS . 'TestHook')));
$this->assertTrue(Hook::has('TestHook'), 'Hook::registerClass does not properly register a given hook');
}
public function testCreateInvalidInstance2()
/**
* @depends testWhetherHooksCanBeRegisteredWithRegisterClass
*/
public function testWhetherMultipleHooksOfTheSameTypeCanBeRegisteredWithRegisterClass()
{
Hook::$BASE_NS = "Tests\\Icinga\\Web\\";
$test = Hook::createInstance("Base","NOTEXIST");
$this->assertNull($test);
}
$firstHook = Mockery::mock(Hook::$BASE_NS . 'TestHook');
$secondHook = Mockery::mock('overload:' . get_class($firstHook));
public function testCreateInvalidInstance3()
{
Hook::$BASE_NS = "Tests\\Icinga\\Web\\";
Hook::register("Base","ErrorProne","Tests\\Icinga\\Web\\ErrorProneHookImplementation");
$test = Hook::createInstance("Base","ErrorProne");
$this->assertNull($test);
}
public function testAll()
{
Hook::$BASE_NS = "Tests\\Icinga\\Web\\";
Hook::registerClass("Base","a","Tests\\Icinga\\Web\\TestHookImplementation");
Hook::registerClass("Base","b","Tests\\Icinga\\Web\\TestHookImplementation");
Hook::registerClass("Base","c","Tests\\Icinga\\Web\\TestHookImplementation");
$this->assertCount(3,Hook::all("Base"));
foreach(Hook::all("Base") as $instance) {
$this->assertInstanceOf("Tests\\Icinga\\Web\\TestHookImplementation",$instance);
}
}
public function testFirst()
{
Hook::$BASE_NS = "Tests\\Icinga\\Web\\";
Hook::registerClass("Base","a","Tests\\Icinga\\Web\\TestHookImplementation");
Hook::registerClass("Base","b","Tests\\Icinga\\Web\\TestHookImplementation");
Hook::registerClass("Base","c","Tests\\Icinga\\Web\\TestHookImplementation");
$this->assertInstanceOf("Tests\\Icinga\\Web\\TestHookImplementation",Hook::first("Base"));
}
public function testRegisterObject()
{
$o1 = Mockery::mock('Some\\Name\\Space\\ObjectHook');
$o1->test = '$123123';
$o2 = Mockery::mock('Some\\Name\\Space\\ObjectHook');
$o2->test = '#456456';
Hook::registerObject('Test', 'o1', $o1);
Hook::registerObject('Test', 'o2', $o2);
$this->assertInstanceOf('Some\\Name\\Space\\ObjectHook', Hook::createInstance('Test', 'o1'));
$this->assertInstanceOf('Some\\Name\\Space\\ObjectHook', Hook::createInstance('Test', 'o2'));
$string = "";
foreach (Hook::all('Test') as $hook) {
$string .= $hook->test;
}
$this->assertEquals('$123123#456456', $string);
Hook::registerClass('TestHook', 'one', get_class($firstHook));
Hook::registerClass('TestHook', 'two', get_class($secondHook));
$this->assertInstanceOf(
get_class($secondHook),
Hook::createInstance('TestHook', 'two'),
'Hook::registerClass is not able to register different hooks of the same type'
);
}
/**
* @expectedException Icinga\Exception\ProgrammingError
* @expectedExceptionMessage object is not an instantiated class
*/
public function testErrorObjectRegistration()
public function testWhetherOnlyClassesCanBeRegisteredAsHookWithRegisterClass()
{
Hook::registerObject('Test', 'e1', 'STRING');
Hook::registerClass('TestHook', __FUNCTION__, 'nope');
}
public function testGetZeroHooks()
public function testWhetherHooksCanBeRegisteredWithRegisterObject()
{
$nh = Hook::all('DOES_NOT_EXIST');
$this->assertInternalType('array', $nh);
$this->assertCount(0, $nh);
Hook::registerObject('TestHook', __FUNCTION__, Mockery::mock(Hook::$BASE_NS . 'TestHook'));
$this->assertTrue(Hook::has('TestHook'), 'Hook::registerObject does not properly register a given hook');
}
/**
* @depends testWhetherHooksCanBeRegisteredWithRegisterObject
*/
public function testWhetherMultipleHooksOfTheSameTypeCanBeRegisteredWithRegisterObject()
{
$firstHook = Mockery::mock(Hook::$BASE_NS . 'TestHook');
$secondHook = Mockery::mock('overload:' . get_class($firstHook));
Hook::registerObject('TestHook', 'one', $firstHook);
Hook::registerObject('TestHook', 'two', $secondHook);
$this->assertInstanceOf(
get_class($secondHook),
Hook::createInstance('TestHook', 'two'),
'Hook::registerObject is not able to register different hooks of the same type'
);
}
/**
* @expectedException Icinga\Exception\ProgrammingError
*/
public function testWhetherOnlyObjectsCanBeRegisteredAsHookWithRegisterObject()
{
Hook::registerObject('TestHook', __FUNCTION__, 'nope');
}
public function testWhetherCreateInstanceReturnsNullIfGivenAnUnknownHookName()
{
$this->assertNull(
Hook::createInstance('not_existing', __FUNCTION__),
'Hook::createInstance does not return null if given an unknown hook'
);
}
/**
* @depends testWhetherHooksCanBeRegisteredWithRegisterClass
*/
public function testWhetherCreateInstanceInitializesHooksInheritingFromAPredefinedAbstractHook()
{
$baseHook = Mockery::mock(Hook::$BASE_NS . 'TestHook');
Hook::registerClass(
'TestHook',
__FUNCTION__,
get_class(Mockery::mock('overload:' . get_class($baseHook)))
);
$this->assertInstanceOf(
get_class($baseHook),
Hook::createInstance('TestHook', __FUNCTION__),
'Hook::createInstance does not initialize hooks inheriting from a predefined abstract hook'
);
}
/**
* @depends testWhetherHooksCanBeRegisteredWithRegisterClass
*/
public function testWhetherCreateInstanceDoesNotInitializeMultipleHooksForASpecificIdentifier()
{
Hook::registerClass('TestHook', __FUNCTION__, get_class(Mockery::mock(Hook::$BASE_NS . 'TestHook')));
$secondHook = Hook::createInstance('TestHook', __FUNCTION__);
$thirdHook = Hook::createInstance('TestHook', __FUNCTION__);
$this->assertSame(
$secondHook,
$thirdHook,
'Hook::createInstance initializes multiple hooks for a specific identifier'
);
}
/**
* @depends testWhetherHooksCanBeRegisteredWithRegisterClass
*/
public function testWhetherCreateInstanceReturnsNullIfHookCannotBeInitialized()
{
Hook::registerClass('TestHook', __FUNCTION__, 'Tests\Icinga\Web\ErrorProneHookImplementation');
$this->assertNull(Hook::createInstance('TestHook', __FUNCTION__));
}
/**
* @expectedException Icinga\Exception\ProgrammingError
* @depends testWhetherHooksCanBeRegisteredWithRegisterClass
*/
public function testWhetherCreateInstanceThrowsAnErrorIfGivenAHookNotInheritingFromAPredefinedAbstractHook()
{
Mockery::mock(Hook::$BASE_NS . 'TestHook');
Hook::registerClass('TestHook', __FUNCTION__, get_class(Mockery::mock('TestHook')));
Hook::createInstance('TestHook', __FUNCTION__);
}
/**
* @depends testWhetherHooksCanBeRegisteredWithRegisterObject
*/
public function testWhetherAllReturnsAllRegisteredHooks()
{
$hook = Mockery::mock(Hook::$BASE_NS . 'TestHook');
Hook::registerObject('TestHook', 'one', $hook);
Hook::registerObject('TestHook', 'two', $hook);
Hook::registerObject('TestHook', 'three', $hook);
$this->assertCount(3, Hook::all('TestHook'), 'Hook::all does not return all registered hooks');
}
public function testWhetherAllReturnsNothingIfGivenAnUnknownHookName()
{
$this->assertEmpty(
Hook::all('not_existing'),
'Hook::all does not return an empty array if given an unknown hook'
);
}
/**
* @depends testWhetherHooksCanBeRegisteredWithRegisterObject
*/
public function testWhetherFirstReturnsTheFirstRegisteredHook()
{
$firstHook = Mockery::mock(Hook::$BASE_NS . 'TestHook');
$secondHook = Mockery::mock(Hook::$BASE_NS . 'TestHook');
Hook::registerObject('TestHook', 'first', $firstHook);
Hook::registerObject('TestHook', 'second', $secondHook);
$this->assertSame(
$firstHook,
Hook::first('TestHook'),
'Hook::first does not return the first registered hook'
);
}
}