summaryrefslogtreecommitdiffstats
path: root/test/php/library/Director/Objects/IcingaHostTest.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--test/php/library/Director/Objects/IcingaHostTest.php771
1 files changed, 771 insertions, 0 deletions
diff --git a/test/php/library/Director/Objects/IcingaHostTest.php b/test/php/library/Director/Objects/IcingaHostTest.php
new file mode 100644
index 0000000..b4902bf
--- /dev/null
+++ b/test/php/library/Director/Objects/IcingaHostTest.php
@@ -0,0 +1,771 @@
+<?php
+
+namespace Tests\Icinga\Module\Director\Objects;
+
+use Icinga\Module\Director\Data\PropertiesFilter\ArrayCustomVariablesFilter;
+use Icinga\Module\Director\Data\PropertiesFilter\CustomVariablesFilter;
+use Icinga\Module\Director\IcingaConfig\IcingaConfig;
+use Icinga\Module\Director\Objects\DirectorDatafield;
+use Icinga\Module\Director\Objects\IcingaHost;
+use Icinga\Module\Director\Objects\IcingaHostGroup;
+use Icinga\Module\Director\Objects\IcingaZone;
+use Icinga\Module\Director\Test\BaseTestCase;
+use Icinga\Exception\IcingaException;
+
+class IcingaHostTest extends BaseTestCase
+{
+ protected $testHostName = '___TEST___host';
+ protected $testDatafieldName = 'test5';
+
+ public function testPropertiesCanBeSet()
+ {
+ $host = $this->host();
+ $host->display_name = 'Something else';
+ $this->assertEquals(
+ $host->display_name,
+ 'Something else'
+ );
+ }
+
+ public function testCanBeReplaced()
+ {
+ $host = $this->host();
+ $newHost = IcingaHost::create(
+ array('display_name' => 'Replaced display'),
+ $this->getDb()
+ );
+
+ $this->assertEquals(
+ count($host->vars()),
+ 4
+ );
+ $this->assertEquals(
+ $host->address,
+ '127.0.0.127'
+ );
+
+ $host->replaceWith($newHost);
+ $this->assertEquals(
+ $host->display_name,
+ 'Replaced display'
+ );
+ $this->assertEquals(
+ $host->address,
+ null
+ );
+
+ $this->assertEquals(
+ count($host->vars()),
+ 0
+ );
+ }
+
+ public function testCanBeMerged()
+ {
+ $host = $this->host();
+ $newHost = IcingaHost::create(
+ array('display_name' => 'Replaced display'),
+ $this->getDb()
+ );
+
+ $this->assertEquals(
+ count($host->vars()),
+ 4
+ );
+ $this->assertEquals(
+ $host->address,
+ '127.0.0.127'
+ );
+
+ $host->merge($newHost);
+ $this->assertEquals(
+ $host->display_name,
+ 'Replaced display'
+ );
+ $this->assertEquals(
+ $host->address,
+ '127.0.0.127'
+ );
+ $this->assertEquals(
+ count($host->vars()),
+ 4
+ );
+ }
+
+ public function testPropertiesCanBePreservedWhenBeingReplaced()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+ $this->host()->store($db);
+ $host = IcingaHost::load($this->testHostName, $db);
+
+ $newHost = IcingaHost::create(
+ array(
+ 'display_name' => 'Replaced display',
+ 'address' => '1.2.2.3',
+ 'vars' => array(
+ 'test1' => 'newstring',
+ 'test2' => 18,
+ 'initially' => 'set and then preserved',
+ )
+ ),
+ $this->getDb()
+ );
+
+ $preserve = array('address', 'vars.test1', 'vars.initially');
+ $host->replaceWith($newHost, $preserve);
+ $this->assertEquals(
+ $host->address,
+ '127.0.0.127'
+ );
+
+ $this->assertEquals(
+ $host->{'vars.test2'},
+ 18
+ );
+
+ $this->assertEquals(
+ $host->vars()->test2->getValue(),
+ 18
+ );
+
+ $this->assertEquals(
+ $host->{'vars.initially'},
+ 'set and then preserved'
+ );
+
+ $this->assertFalse(
+ array_key_exists('address', $host->getModifiedProperties()),
+ 'Preserved property stays unmodified'
+ );
+
+ $newHost->set('vars.initially', 'changed later on');
+ $newHost->set('vars.test2', 19);
+
+ $host->replaceWith($newHost, $preserve);
+ $this->assertEquals(
+ $host->{'vars.initially'},
+ 'set and then preserved'
+ );
+
+ $this->assertEquals(
+ $host->get('vars.test2'),
+ 19
+ );
+
+
+ $host->delete();
+ }
+
+ public function testDistinctCustomVarsCanBeSetWithoutSideEffects()
+ {
+ $host = $this->host();
+ $host->set('vars.test2', 18);
+ $this->assertEquals(
+ $host->vars()->test1->getValue(),
+ 'string'
+ );
+ $this->assertEquals(
+ $host->vars()->test2->getValue(),
+ 18
+ );
+ $this->assertEquals(
+ $host->vars()->test3->getValue(),
+ false
+ );
+ }
+
+ public function testVarsArePersisted()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+ $this->host()->store($db);
+ $host = IcingaHost::load($this->testHostName, $db);
+ $this->assertEquals(
+ $host->vars()->test1->getValue(),
+ 'string'
+ );
+ $this->assertEquals(
+ $host->vars()->test2->getValue(),
+ 17
+ );
+ $this->assertEquals(
+ $host->vars()->test3->getValue(),
+ false
+ );
+ $this->assertEquals(
+ $host->vars()->test4->getValue(),
+ (object) array(
+ 'this' => 'is',
+ 'a' => array(
+ 'dict',
+ 'ionary'
+ )
+ )
+ );
+ }
+
+ public function testRendersCorrectly()
+ {
+ $this->assertEquals(
+ (string) $this->host(),
+ $this->loadRendered('host1')
+ );
+ }
+
+ public function testGivesPlainObjectWithInvalidUnresolvedDependencies()
+ {
+ $props = $this->getDummyRelatedProperties();
+
+ $host = $this->host();
+ foreach ($props as $k => $v) {
+ $host->$k = $v;
+ }
+
+ $plain = $host->toPlainObject();
+ foreach ($props as $k => $v) {
+ $this->assertEquals($plain->$k, $v);
+ }
+ }
+
+ public function testCorrectlyStoresLazyRelations()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+ $db = $this->getDb();
+ $host = $this->host();
+ $host->zone = '___TEST___zone';
+ $this->assertEquals(
+ '___TEST___zone',
+ $host->zone
+ );
+
+ $zone = $this->newObject('zone', '___TEST___zone');
+ $zone->store($db);
+
+ $host->store($db);
+ $host->delete();
+ $zone->delete();
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testFailsToStoreWithMissingLazyRelations()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+ $db = $this->getDb();
+ $host = $this->host();
+ $host->zone = '___TEST___zone';
+ $host->store($db);
+ }
+
+ public function testHandlesUnmodifiedProperties()
+ {
+ $this->markTestSkipped('Currently broken, needs to be fixed');
+
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+ $host = $this->host();
+ $host->store($db);
+
+ $parent = $this->newObject('host', '___TEST___parent');
+ $parent->store($db);
+ $host->imports = '___TEST___parent';
+
+ $host->store($db);
+
+ $plain = $host->getPlainUnmodifiedObject();
+ $this->assertEquals(
+ 'string',
+ $plain->vars->test1
+ );
+ $host->vars()->set('test1', 'nada');
+
+ $host->store();
+
+ $plain = $host->getPlainUnmodifiedObject();
+ $this->assertEquals(
+ 'nada',
+ $plain->vars->test1
+ );
+
+ $host->vars()->set('test1', 'string');
+ $plain = $host->getPlainUnmodifiedObject();
+ $this->assertEquals(
+ 'nada',
+ $plain->vars->test1
+ );
+
+ $plain = $host->getPlainUnmodifiedObject();
+ $test = IcingaHost::create((array) $plain);
+
+ $this->assertEquals(
+ $this->loadRendered('host3'),
+ (string) $test
+ );
+
+ $host->delete();
+ $parent->delete();
+ }
+
+ public function testRendersWithInvalidUnresolvedDependencies()
+ {
+ $newHost = $this->host();
+ $newHost->zone = 'invalid';
+ $newHost->check_command = 'unknown';
+ $newHost->event_command = 'What event?';
+ $newHost->check_period = 'Not time is a good time @ nite';
+ $newHost->command_endpoint = 'nirvana';
+
+ $this->assertEquals(
+ (string) $newHost,
+ $this->loadRendered('host2')
+ );
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testFailsToStoreWithInvalidUnresolvedDependencies()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $host = $this->host();
+ $host->zone = 'invalid';
+ $host->store($this->getDb());
+ }
+
+ public function testRendersToTheCorrectZone()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+ $host = $this->host()->setConnection($db);
+ $masterzone = $db->getMasterZoneName();
+
+ $config = new IcingaConfig($db);
+ $host->renderToConfig($config);
+ $this->assertEquals(
+ array('zones.d/' . $masterzone . '/hosts.conf'),
+ $config->getFileNames()
+ );
+
+ $zone = $this->newObject('zone', '___TEST___zone');
+ $zone->store($db);
+
+ $config = new IcingaConfig($db);
+ $host->zone = '___TEST___zone';
+ $host->renderToConfig($config);
+ $this->assertEquals(
+ array('zones.d/___TEST___zone/hosts.conf'),
+ $config->getFileNames()
+ );
+
+ $host->has_agent = true;
+ $host->master_should_connect = true;
+ $host->accept_config = true;
+
+ $config = new IcingaConfig($db);
+ $host->renderToConfig($config);
+ $this->assertEquals(
+ array(
+ 'zones.d/___TEST___zone/hosts.conf',
+ 'zones.d/___TEST___zone/agent_endpoints.conf',
+ 'zones.d/___TEST___zone/agent_zones.conf'
+ ),
+ $config->getFileNames()
+ );
+
+ $host->object_type = 'template';
+ $host->zone_id = null;
+
+ $config = new IcingaConfig($db);
+ $host->renderToConfig($config);
+ $this->assertEquals(
+ array('zones.d/director-global/host_templates.conf'),
+ $config->getFileNames()
+ );
+ }
+
+ public function testWhetherTwoHostsCannotBeStoredWithTheSameApiKey()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+ $a = IcingaHost::create(array(
+ 'object_name' => '___TEST___a',
+ 'object_type' => 'object',
+ 'api_key' => 'a'
+ ), $db);
+ $b = IcingaHost::create(array(
+ 'object_name' => '___TEST___b',
+ 'object_type' => 'object',
+ 'api_key' => 'a'
+ ), $db);
+
+ $a->store();
+ try {
+ $b->store();
+ } catch (\RuntimeException $e) {
+ $msg = $e->getMessage();
+ $matchMysql = strpos(
+ $msg,
+ "Duplicate entry 'a' for key 'api_key'"
+ ) !== false;
+
+ $matchPostgres = strpos(
+ $msg,
+ 'Unique violation'
+ ) !== false;
+
+ $this->assertTrue(
+ $matchMysql || $matchPostgres,
+ 'Exception message does not tell about unique constraint violation'
+ );
+ $a->delete();
+ }
+ }
+
+ public function testWhetherHostCanBeLoadedWithValidApiKey()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+ $a = IcingaHost::create(array(
+ 'object_name' => '___TEST___a',
+ 'object_type' => 'object',
+ 'api_key' => 'a1a1a1'
+ ), $db);
+ $b = IcingaHost::create(array(
+ 'object_name' => '___TEST___b',
+ 'object_type' => 'object',
+ 'api_key' => 'b1b1b1'
+ ), $db);
+ $a->store();
+ $b->store();
+
+ $this->assertEquals(
+ IcingaHost::loadWithApiKey('b1b1b1', $db)->object_name,
+ '___TEST___b'
+ );
+
+ $a->delete();
+ $b->delete();
+ }
+
+ /**
+ * @expectedException \Icinga\Exception\NotFoundError
+ */
+ public function testWhetherInvalidApiKeyThrows404()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+ IcingaHost::loadWithApiKey('No___such___key', $db);
+ }
+
+ public function testEnumProperties()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+ $properties = IcingaHost::enumProperties($db);
+
+ $this->assertEquals(
+ array(
+ 'Host properties' => $this->getDefaultHostProperties()
+ ),
+ $properties
+ );
+ }
+
+ public function testEnumPropertiesWithCustomVars()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+
+ $host = $this->host();
+ $host->store($db);
+
+ $properties = IcingaHost::enumProperties($db);
+ $this->assertEquals(
+ array(
+ 'Host properties' => $this->getDefaultHostProperties(),
+ 'Custom variables' => array(
+ 'vars.test1' => 'test1',
+ 'vars.test2' => 'test2',
+ 'vars.test3' => 'test3',
+ 'vars.test4' => 'test4'
+ )
+ ),
+ $properties
+ );
+ }
+
+ public function testEnumPropertiesWithPrefix()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+
+ $host = $this->host();
+ $host->store($db);
+
+ $properties = IcingaHost::enumProperties($db, 'host.');
+ $this->assertEquals(
+ array(
+ 'Host properties' => $this->getDefaultHostProperties('host.'),
+ 'Custom variables' => array(
+ 'host.vars.test1' => 'test1',
+ 'host.vars.test2' => 'test2',
+ 'host.vars.test3' => 'test3',
+ 'host.vars.test4' => 'test4'
+ )
+ ),
+ $properties
+ );
+ }
+
+ public function testEnumPropertiesWithFilter()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+
+ DirectorDatafield::create(array(
+ 'varname' => $this->testDatafieldName,
+ 'caption' => 'Blah',
+ 'description' => '',
+ 'datatype' => 'Icinga\Module\Director\DataType\DataTypeArray',
+ 'format' => 'json'
+ ))->store($db);
+
+ $host = $this->host();
+ $host->{'vars.test5'} = array('a', '1');
+ $host->store($db);
+
+ $properties = IcingaHost::enumProperties($db, '', new CustomVariablesFilter());
+ $this->assertEquals(
+ array(
+ 'Custom variables' => array(
+ 'vars.test1' => 'test1',
+ 'vars.test2' => 'test2',
+ 'vars.test3' => 'test3',
+ 'vars.test4' => 'test4',
+ 'vars.test5' => 'test5 (Blah)'
+ )
+ ),
+ $properties
+ );
+ }
+
+ public function testEnumPropertiesWithArrayFilter()
+ {
+ if ($this->skipForMissingDb()) {
+ return;
+ }
+
+ $db = $this->getDb();
+
+ DirectorDatafield::create(array(
+ 'varname' => $this->testDatafieldName,
+ 'caption' => 'Blah',
+ 'description' => '',
+ 'datatype' => 'Icinga\Module\Director\DataType\DataTypeArray',
+ 'format' => 'json'
+ ))->store($db);
+
+ $host = $this->host();
+ $host->{'vars.test5'} = array('a', '1');
+ $host->store($db);
+
+ $properties = IcingaHost::enumProperties($db, '', new ArrayCustomVariablesFilter());
+ $this->assertEquals(
+ array(
+ 'Custom variables' => array(
+ 'vars.test5' => 'test5 (Blah)'
+ )
+ ),
+ $properties
+ );
+ }
+
+ public function testMergingObjectKeepsGroupsIfNotGiven()
+ {
+ $one = IcingaHostGroup::create([
+ 'object_name' => 'one',
+ 'object_type' => 'object',
+ ]);
+ $two = IcingaHostGroup::create([
+ 'object_name' => 'two',
+ 'object_type' => 'object',
+ ]);
+ $a = IcingaHost::create([
+ 'object_name' => 'one',
+ 'object_type' => 'object',
+ 'imports' => [],
+ 'address' => '127.0.0.2',
+ 'groups' => [$one, $two]
+ ]);
+
+ $b = IcingaHost::create([
+ 'object_name' => 'one',
+ 'object_type' => 'object',
+ 'imports' => [],
+ 'address' => '127.0.0.42',
+ ]);
+
+ $a->merge($b);
+ $this->assertEquals(
+ '127.0.0.42',
+ $a->get('address')
+ );
+ $this->assertEquals(
+ ['one', 'two'],
+ $a->getGroups()
+ );
+ }
+
+ protected function getDummyRelatedProperties()
+ {
+ return array(
+ 'zone' => 'invalid',
+ 'check_command' => 'unknown',
+ 'event_command' => 'What event?',
+ 'check_period' => 'Not time is a good time @ nite',
+ 'command_endpoint' => 'nirvana',
+ );
+ }
+
+ protected function host()
+ {
+ return IcingaHost::create(array(
+ 'object_name' => $this->testHostName,
+ 'object_type' => 'object',
+ 'address' => '127.0.0.127',
+ 'display_name' => 'Whatever',
+ 'vars' => array(
+ 'test1' => 'string',
+ 'test2' => 17,
+ 'test3' => false,
+ 'test4' => (object) array(
+ 'this' => 'is',
+ 'a' => array(
+ 'dict',
+ 'ionary'
+ )
+ )
+ )
+ ), $this->getDb());
+ }
+
+ protected function getDefaultHostProperties($prefix = '')
+ {
+ return array(
+ "${prefix}name" => "name",
+ "${prefix}action_url" => "action_url",
+ "${prefix}address" => "address",
+ "${prefix}address6" => "address6",
+ "${prefix}api_key" => "api_key",
+ "${prefix}check_command" => "check_command",
+ "${prefix}check_interval" => "check_interval",
+ "${prefix}check_period" => "check_period",
+ "${prefix}check_timeout" => "check_timeout",
+ "${prefix}command_endpoint" => "command_endpoint",
+ "${prefix}display_name" => "display_name",
+ "${prefix}enable_active_checks" => "enable_active_checks",
+ "${prefix}enable_event_handler" => "enable_event_handler",
+ "${prefix}enable_flapping" => "enable_flapping",
+ "${prefix}enable_notifications" => "enable_notifications",
+ "${prefix}enable_passive_checks" => "enable_passive_checks",
+ "${prefix}enable_perfdata" => "enable_perfdata",
+ "${prefix}event_command" => "event_command",
+ "${prefix}flapping_threshold_high" => "flapping_threshold_high",
+ "${prefix}flapping_threshold_low" => "flapping_threshold_low",
+ "${prefix}icon_image" => "icon_image",
+ "${prefix}icon_image_alt" => "icon_image_alt",
+ "${prefix}max_check_attempts" => "max_check_attempts",
+ "${prefix}notes" => "notes",
+ "${prefix}notes_url" => "notes_url",
+ "${prefix}retry_interval" => "retry_interval",
+ "${prefix}volatile" => "volatile",
+ "${prefix}zone" => "zone",
+ "${prefix}groups" => "Groups",
+ "${prefix}templates" => "templates"
+ );
+ }
+ protected function loadRendered($name)
+ {
+ return file_get_contents(__DIR__ . '/rendered/' . $name . '.out');
+ }
+
+ public function tearDown()
+ {
+ if ($this->hasDb()) {
+ $db = $this->getDb();
+ $kill = array($this->testHostName, '___TEST___parent', '___TEST___a', '___TEST___b');
+ foreach ($kill as $name) {
+ if (IcingaHost::exists($name, $db)) {
+ IcingaHost::load($name, $db)->delete();
+ }
+ }
+
+ $kill = array('___TEST___zone');
+ foreach ($kill as $name) {
+ if (IcingaZone::exists($name, $db)) {
+ IcingaZone::load($name, $db)->delete();
+ }
+ }
+
+ $this->deleteDatafields();
+ }
+ }
+
+ protected function deleteDatafields()
+ {
+ $db = $this->getDb();
+ $dbAdapter = $db->getDbAdapter();
+ $kill = array($this->testDatafieldName);
+
+ foreach ($kill as $name) {
+ $query = $dbAdapter->select()
+ ->from('director_datafield')
+ ->where('varname = ?', $name);
+ foreach (DirectorDatafield::loadAll($db, $query, 'id') as $datafield) {
+ $datafield->delete();
+ }
+ }
+ }
+}