icingaweb2-module-director/test/php/library/Director/Objects/IcingaHostTest.php

724 lines
20 KiB
PHP

<?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\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->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->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',
)
)
);
$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 \Icinga\Exception\NotFoundError
*/
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 \Icinga\Exception\NotFoundError
*/
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 (IcingaException $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
);
}
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'
)
)
)
));
}
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}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" => "flapping_threshold",
"${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"
);
}
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();
}
}
}
}