diff options
Diffstat (limited to '')
-rw-r--r-- | test/php/library/Icingadb/Common/MacrosTest.php | 174 | ||||
-rw-r--r-- | test/php/library/Icingadb/Common/StateBadgesTest.php | 86 | ||||
-rw-r--r-- | test/php/library/Icingadb/Model/CustomvarFlatTest.php | 121 | ||||
-rw-r--r-- | test/php/library/Icingadb/Util/PerfdataSetTest.php | 120 | ||||
-rw-r--r-- | test/php/library/Icingadb/Util/PerfdataTest.php | 591 | ||||
-rw-r--r-- | test/php/library/Icingadb/Util/ThresholdRangeTest.php | 343 |
6 files changed, 1435 insertions, 0 deletions
diff --git a/test/php/library/Icingadb/Common/MacrosTest.php b/test/php/library/Icingadb/Common/MacrosTest.php new file mode 100644 index 0000000..f998da8 --- /dev/null +++ b/test/php/library/Icingadb/Common/MacrosTest.php @@ -0,0 +1,174 @@ +<?php + +/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */ + +namespace Tests\Icinga\Modules\Icingadb\Common; + +use Icinga\Module\Icingadb\Common\Macros; +use Icinga\Module\Icingadb\Compat\CompatHost; +use Icinga\Module\Icingadb\Compat\CompatService; +use Icinga\Module\Icingadb\Model\Host; +use Icinga\Module\Icingadb\Model\Service; +use ipl\Orm\Query; +use ipl\Orm\ResultSet; +use PHPUnit\Framework\TestCase; + +class MacrosTest extends TestCase +{ + use Macros; + + const VARS = [ + 'os' => "Ubuntu", + 'days[0]' => 'mo', + 'days[1]' => 'tue', + 'days[2]' => 'wed', + 'days[3]' => 'thu', + 'days[4]' => 'fr' + ]; + + public function testHostMacros() + { + $host = new Host(); + $host->name = 'test'; + $host->address = '1.1.1.1'; + $host->address6 = '::1'; + $host->vars = self::VARS; + + $host->hostgroup = new Query(); + + $this->performHostMacroTests($host, $host); + } + + public function testHostMacrosOnCompatObject() + { + if (! class_exists('Icinga\Module\Monitoring\Object\Host')) { + $this->markTestSkipped('This test requires the monitoring module'); + } + + $host = new Host(); + $host->name = 'test'; + $host->address = '1.1.1.1'; + $host->address6 = '::1'; + $host->vars = self::VARS; + + $host->hostgroup = new Query(); + + $compatHost = new CompatHost($host); + + $this->performHostMacroTests($compatHost, $host); + } + + protected function performHostMacroTests($host, $source) + { + $this->assertEquals($source->name, $this->expandMacros('$host.name$', $host)); + $this->assertEquals($source->name, $this->expandMacros('$name$', $host)); + $this->assertEquals($source->address, $this->expandMacros('$host.address$', $host)); + $this->assertEquals($source->address6, $this->expandMacros('$host.address6$', $host)); + + // A Host can have more than one hostgroups + $this->assertEquals('$host.hostgroup$', $this->expandMacros('$host.hostgroup$', $host)); + $this->assertEquals('$host.hostgroup.name$', $this->expandMacros('$host.hostgroup.name$', $host)); + + // Host custom vars + $this->assertEquals($source->vars['os'], $this->expandMacros('$host.vars.os$', $host)); + $this->assertEquals($source->vars['os'], $this->expandMacros('$vars.os$', $host)); + $this->assertEquals($source->vars['days[2]'], $this->expandMacros('$vars.days[2]$', $host)); + $this->assertEquals($source->vars['days[4]'], $this->expandMacros('$host.vars.days[4]$', $host)); + + // Host to service relation + $this->assertEquals('$service.name$', $this->expandMacros('$service.name$', $host)); + $this->assertEquals('$service.address$', $this->expandMacros('$service.address$', $host)); + + // Service custom vars + $this->assertEquals('$service.vars.os$', $this->expandMacros('$service.vars.os$', $host)); + $this->assertEquals('$service.vars.days[0]$', $this->expandMacros('$service.vars.days[0]$', $host)); + $this->assertEquals('$service.vars.days[2]$', $this->expandMacros('$service.vars.days[2]$', $host)); + } + + public function testServiceMacros() + { + $service = new Service(); + $service->name = 'test-service'; + $service->description = 'A test service'; + $service->vars = self::VARS; + + $service->servicegroup = new Query(); + + $host = new Host(); + $host->name = 'test'; + $host->address = '1.1.1.1'; + $host->hostgroup = new ResultSet(new \ArrayIterator()); + $host->vars = self::VARS; + + $service->host = $host; + + $this->performServiceMacroTests($service, $service); + } + + public function testServiceMacrosOnCompatObject() + { + if (! class_exists('Icinga\Module\Monitoring\Object\Service')) { + $this->markTestSkipped('This test requires the monitoring module'); + } + + $service = new Service(); + $service->name = 'test-service'; + $service->description = 'A test service'; + $service->vars = self::VARS; + + $service->servicegroup = new Query(); + + $host = new Host(); + $host->name = 'test'; + $host->address = '1.1.1.1'; + $host->hostgroup = new ResultSet(new \ArrayIterator()); + $host->vars = self::VARS; + + $service->host = $host; + + $compatService = new CompatService($service); + + $this->performServiceMacroTests($compatService, $service); + } + + protected function performServiceMacroTests($service, $source) + { + $this->assertEquals($source->name, $this->expandMacros('$service.name$', $service)); + $this->assertEquals($source->name, $this->expandMacros('$name$', $service)); + $this->assertEquals($source->description, $this->expandMacros('$service.description$', $service)); + + // A Service can have more than one hostgroups + $this->assertEquals( + '$service.servicegroup$', + $this->expandMacros('$service.servicegroup$', $service) + ); + $this->assertEquals( + '$service.servicegroup.name$', + $this->expandMacros('$service.servicegroup.name$', $service) + ); + + // Service custom vars + $this->assertEquals($source->vars['os'], $this->expandMacros('$service.vars.os$', $service)); + $this->assertEquals($source->vars['os'], $this->expandMacros('$vars.os$', $service)); + $this->assertEquals($source->vars['days[2]'], $this->expandMacros('$vars.days[2]$', $service)); + $this->assertEquals($source->vars['days[4]'], $this->expandMacros('$service.vars.days[4]$', $service)); + + $this->assertEquals($source->host->name, $this->expandMacros('$host.name$', $service)); + $this->assertEquals($source->host->address, $this->expandMacros('$host.address$', $service)); + + // Host custom vars + $this->assertEquals($source->host->vars['os'], $this->expandMacros('$host.vars.os$', $service)); + $this->assertEquals($source->host->vars['days[0]'], $this->expandMacros('$host.vars.days[0]$', $service)); + $this->assertEquals($source->host->vars['days[3]'], $this->expandMacros('$host.vars.days[3]$', $service)); + + // A Host can have more than one hostgroups + $this->assertEquals( + '$host.hostgroup$', + $this->expandMacros('$host.hostgroup$', $service) + ); + $this->assertEquals( + '$host.hostgroup.name$', + $this->expandMacros('$host.hostgroup.name$', $service) + ); + } +} diff --git a/test/php/library/Icingadb/Common/StateBadgesTest.php b/test/php/library/Icingadb/Common/StateBadgesTest.php new file mode 100644 index 0000000..b535e65 --- /dev/null +++ b/test/php/library/Icingadb/Common/StateBadgesTest.php @@ -0,0 +1,86 @@ +<?php + +/* Icinga DB Web | (c) 2023 Icinga GmbH | GPLv2 */ + +namespace Tests\Icinga\Modules\Icingadb\Common; + +use Icinga\Module\Icingadb\Common\StateBadges; +use Icinga\Web\UrlParams; +use ipl\Stdlib\Filter; +use ipl\Web\Filter\QueryString; +use ipl\Web\Url; +use PHPUnit\Framework\TestCase; + +class StateBadgesTest extends TestCase +{ + public function testCreateLinkRendersBaseFilterCorrectly() + { + $stateBadges = $this->createStateBadges() + ->setBaseFilter(Filter::any( + Filter::equal('foo', 'bar'), + Filter::equal('bar', 'foo') + )); + + $link = $stateBadges->createLink('test', Filter::equal('rab', 'oof')); + + $this->assertSame( + 'rab=oof&(foo=bar|bar=foo)', + $link->getUrl()->getQueryString() + ); + } + + private function createStateBadges() + { + $queryString = null; + + $urlMock = $this->createConfiguredMock(Url::class, [ + 'getBasePath' => 'test', + 'getParams' => $this->createConfiguredMock(UrlParams::class, [ + 'toArray' => [] + ]) + ]); + $urlMock->method('setFilter')->willReturnCallback( + function ($qs) use ($urlMock, &$queryString) { + $queryString = QueryString::render($qs); + + return $urlMock; + } + ); + $urlMock->method('getQueryString')->willReturnCallback( + function () use (&$queryString) { + return $queryString; + } + ); + + return new class ($urlMock) extends StateBadges { + private $urlMock; + + public function __construct($urlMock) + { + $this->urlMock = $urlMock; + + parent::__construct((object) []); + } + + protected function getBaseUrl(): Url + { + return $this->urlMock; + } + + protected function getType(): string + { + return 'test'; + } + + protected function getPrefix(): string + { + return 'Test'; + } + + protected function getStateInt(string $state): int + { + return 0; + } + }; + } +} diff --git a/test/php/library/Icingadb/Model/CustomvarFlatTest.php b/test/php/library/Icingadb/Model/CustomvarFlatTest.php new file mode 100644 index 0000000..a69f578 --- /dev/null +++ b/test/php/library/Icingadb/Model/CustomvarFlatTest.php @@ -0,0 +1,121 @@ +<?php + +/* Icinga DB Web | (c) 2023 Icinga GmbH | GPLv2 */ + +namespace Tests\Icinga\Modules\Icingadb\Model; + +use Icinga\Module\Icingadb\Model\CustomvarFlat; +use PHPUnit\Framework\TestCase; + +class CustomvarFlatTest extends TestCase +{ + const EMPTY_TEST_SOURCE = [ + ["dict.not_empty.foo","bar","dict","{\"empty\":{},\"not_empty\":{\"foo\":\"bar\"}}"], + ["dict.empty",null,"dict","{\"empty\":{},\"not_empty\":{\"foo\":\"bar\"}}"], + ["list[1]",null,"list","[[\"foo\",\"bar\"],[]]"], + ["list[0][0]","foo","list","[[\"foo\",\"bar\"],[]]"], + ["list[0][1]","bar","list","[[\"foo\",\"bar\"],[]]"], + ["empty_list",null,"empty_list","[]"], + ["empty_dict",null,"empty_dict","{}"], + ["null","null","null","null"] + ]; + + const EMPTY_TEST_RESULT = [ + "dict" => [ + "not_empty" => [ + "foo" => "bar" + ], + "empty" => [] + ], + "list" => [ + ["foo", "bar"], + [] + ], + "empty_list" => [], + "empty_dict" => [], + "null" => "null" + ]; + + const SPECIAL_CHAR_TEST_SOURCE = [ + [ + "vhosts.xxxxxxxxxxxxx.mgmt.xxxxxx.com.http_port", + "443", + "vhosts", + "{\"xxxxxxxxxxxxx.mgmt.xxxxxx.com\":{\"http_port\":\"443\"}}" + ], + ["ex.ample.com.bla","blub","ex","{\"ample.com\":{\"bla\":\"blub\"}}"], + ["example[1]","zyx","example[1]","\"zyx\""], + ["example.0.org","xyz","example.0.org","\"xyz\""], + ["ob.je.ct","***","ob","{\"je\":{\"ct\":\"tcejbo\"}}"], + ["real_list[2]","three","real_list","[\"one\",\"two\",\"three\"]"], + ["real_list[1]","two","real_list","[\"one\",\"two\",\"three\"]"], + ["real_list[0]","one","real_list","[\"one\",\"two\",\"three\"]"], + ["[1].2.[3].4.[5].6","123456","[1].2","{\"[3].4\":{\"[5].6\":123456}}"], + ["ex.ample.com","cba","ex.ample.com","\"cba\""], + ["[4]","four","[4]","\"four\""] + ]; + + const SPECIAL_CHAR_TEST_RESULT = [ + "vhosts" => [ + "xxxxxxxxxxxxx.mgmt.xxxxxx.com" => [ + "http_port" => 443 + ] + ], + "ex" => [ + "ample.com" => [ + "bla" => "blub" + ] + ], + "example[1]" => "zyx", + "example.0.org" => "xyz", + "ob" => [ + "je" => [ + "ct" => "***" + ] + ], + "real_list" => [ + "one", + "two", + "three" + ], + "[1].2" => [ + "[3].4" => [ + "[5].6" => "123456" + ] + ], + "ex.ample.com" => "cba", + "[4]" => "four" + ]; + + public function testUnflatteningOfEmptyCustomVariables() + { + $this->assertEquals( + self::EMPTY_TEST_RESULT, + (new CustomvarFlat())->unFlattenVars($this->transformSource(self::EMPTY_TEST_SOURCE)), + "Empty custom variables are not correctly unflattened" + ); + } + + public function testUnflatteningOfCustomVariablesWithSpecialCharacters() + { + $this->assertEquals( + self::SPECIAL_CHAR_TEST_RESULT, + (new CustomvarFlat())->unFlattenVars($this->transformSource(self::SPECIAL_CHAR_TEST_SOURCE)), + "Custom variables with special characters are not correctly unflattened" + ); + } + + protected function transformSource(array $source): \Generator + { + foreach ($source as $data) { + yield (object) [ + 'flatname' => $data[0], + 'flatvalue' => $data[1], + 'customvar' => (object) [ + 'name' => $data[2], + 'value' => $data[3] + ] + ]; + } + } +} diff --git a/test/php/library/Icingadb/Util/PerfdataSetTest.php b/test/php/library/Icingadb/Util/PerfdataSetTest.php new file mode 100644 index 0000000..618c29a --- /dev/null +++ b/test/php/library/Icingadb/Util/PerfdataSetTest.php @@ -0,0 +1,120 @@ +<?php + +/* Icinga DB Web | (c) 2023 Icinga GmbH | GPLv2 */ + +namespace Tests\Icinga\Module\Icingadb\Util; + +use Icinga\Module\Icingadb\Util\PerfDataSet; +use PHPUnit\Framework\TestCase; +use Tests\Icinga\Module\Icingadb\Lib\PerfdataSetWithPublicData; + +class PerfdataSetTest extends TestCase +{ + public function testWhetherValidSimplePerfdataLabelsAreProperlyParsed() + { + $pset = PerfdataSetWithPublicData::fromString('key1=val1 key2=val2 key3 =val3'); + $this->assertSame( + 'key1', + $pset->perfdata[0]->getLabel(), + 'PerfdataSet does not correctly parse valid simple labels' + ); + $this->assertSame( + 'key2', + $pset->perfdata[1]->getLabel(), + 'PerfdataSet does not correctly parse valid simple labels' + ); + $this->assertSame( + 'key3', + $pset->perfdata[2]->getLabel(), + 'PerfdataSet does not correctly parse valid simple labels' + ); + } + + public function testWhetherNonQuotedPerfdataLablesWithSpacesAreProperlyParsed() + { + $pset = PerfdataSetWithPublicData::fromString('key 1=val1 key 1 + 1=val2'); + $this->assertSame( + 'key 1', + $pset->perfdata[0]->getLabel(), + 'PerfdataSet does not correctly parse non quoted labels with spaces' + ); + $this->assertSame( + 'key 1 + 1', + $pset->perfdata[1]->getLabel(), + 'PerfdataSet does not correctly parse non quoted labels with spaces' + ); + } + + public function testWhetherValidQuotedPerfdataLabelsAreProperlyParsed() + { + $pset = PerfdataSetWithPublicData::fromString('\'key 1\'=val1 "key 2"=val2 \'a=b\'=0%;;2'); + $this->assertSame( + 'key 1', + $pset->perfdata[0]->getLabel(), + 'PerfdataSet does not correctly parse valid quoted labels' + ); + $this->assertSame( + 'key 2', + $pset->perfdata[1]->getLabel(), + 'PerfdataSet does not correctly parse valid quoted labels' + ); + $this->assertSame( + 'a=b', + $pset->perfdata[2]->getLabel(), + 'PerfdataSet does not correctly parse labels with equal signs' + ); + } + + public function testWhetherInvalidQuotedPerfdataLabelsAreProperlyParsed() + { + $pset = PerfdataSetWithPublicData::fromString('\'key 1=1 key 2"=2'); + $this->assertSame( + 'key 1', + $pset->perfdata[0]->getLabel(), + 'PerfdataSet does not correctly parse invalid quoted labels' + ); + $this->assertSame( + 'key 2"', + $pset->perfdata[1]->getLabel(), + 'PerfdataSet does not correctly parse invalid quoted labels' + ); + $pset = PerfdataSetWithPublicData::fromString('"key 1=1 "key 2"=2'); + $this->assertSame( + 'key 1=1', + $pset->perfdata[0]->getLabel(), + 'PerfdataSet does not correctly parse invalid quoted labels' + ); + $this->assertNull( + $pset->perfdata[0]->getValue() + ); + $this->assertSame( + '2"', + $pset->perfdata[1]->getLabel(), + 'PerfdataSet does not correctly parse invalid quoted labels' + ); + $this->assertSame( + 2.0, + $pset->perfdata[1]->getValue() + ); + } + + /** + * @depends testWhetherValidSimplePerfdataLabelsAreProperlyParsed + */ + public function testWhetherAPerfdataSetIsIterable() + { + $pset = PerfdataSet::fromString('key=value'); + foreach ($pset as $p) { + $this->assertSame('key', $p->getLabel()); + return; + } + + $this->fail('PerfdataSet objects cannot be iterated'); + } + + public function testWhetherPerfdataSetsCanBeInitializedWithEmptyStrings() + { + $pset = PerfdataSetWithPublicData::fromString(''); + $this->assertEmpty($pset->perfdata, 'PerfdataSet::fromString does not accept emtpy strings'); + } +} diff --git a/test/php/library/Icingadb/Util/PerfdataTest.php b/test/php/library/Icingadb/Util/PerfdataTest.php new file mode 100644 index 0000000..5a63825 --- /dev/null +++ b/test/php/library/Icingadb/Util/PerfdataTest.php @@ -0,0 +1,591 @@ +<?php + +/* Icinga DB Web | (c) 2023 Icinga GmbH | GPLv2 */ + +namespace Tests\Icinga\Module\Icingadb\Util; + +use Icinga\Module\Icingadb\Util\PerfData; +use PHPUnit\Framework\TestCase; + +class PerfdataTest extends TestCase +{ + public function testWhetherFromStringThrowsExceptionWhenGivenAnEmptyString() + { + $this->expectException(\InvalidArgumentException::class); + + Perfdata::fromString(''); + } + + public function testWhetherFromStringThrowsExceptionWhenGivenAnInvalidString() + { + $this->expectException(\InvalidArgumentException::class); + + Perfdata::fromString('test'); + } + + public function testWhetherFromStringParsesAGivenStringCorrectly() + { + $p = Perfdata::fromString('key=1234'); + $this->assertSame( + 'key', + $p->getLabel(), + 'Perfdata::fromString does not properly parse performance data labels' + ); + $this->assertSame( + 1234.0, + $p->getValue(), + 'Perfdata::fromString does not properly parse performance data values' + ); + } + + /** + * @depends testWhetherFromStringParsesAGivenStringCorrectly + */ + public function testWhetherGetValueReturnsValidValues() + { + $this->assertSame( + 1337.0, + Perfdata::fromString('test=1337')->getValue(), + 'Perfdata::getValue does not return correct values' + ); + $this->assertSame( + 1337.0, + Perfdata::fromString('test=1337;;;;')->getValue(), + 'Perfdata::getValue does not return correct values' + ); + } + + /** + * @depends testWhetherFromStringParsesAGivenStringCorrectly + */ + public function testWhetherDecimalValuesAreCorrectlyParsed() + { + $this->assertSame( + 1337.5, + Perfdata::fromString('test=1337.5')->getValue(), + 'Perfdata objects do not parse decimal values correctly' + ); + $this->assertSame( + 1337.5, + Perfdata::fromString('test=1337.5B')->getValue(), + 'Perfdata objects do not parse decimal values correctly' + ); + } + + /** + * @depends testWhetherFromStringParsesAGivenStringCorrectly + */ + public function testWhetherGetValueReturnsNullForInvalidOrUnknownValues() + { + $this->assertNull( + Perfdata::fromString('test=U')->getValue(), + 'Perfdata::getValue does not return null for unknown values' + ); + $this->assertNull( + Perfdata::fromString('test=i am not a value')->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertNull( + PerfData::fromString('test=')->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertNull( + PerfData::fromString('test=-kW')->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertNull( + PerfData::fromString('test=kW')->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertNull( + PerfData::fromString('test=-')->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + } + + /** + * @depends testWhetherFromStringParsesAGivenStringCorrectly + */ + public function testWhetherUnitOfUnkownValuesIsCorrectlyIdentified() + { + $this->assertNull( + Perfdata::fromString('test=U')->getUnit(), + 'Perfdata::getUnit does not return null for unknown values' + ); + $this->assertNull( + Perfdata::fromString('test=i am not a value')->getUnit(), + 'Perfdata::getUnit does not return null for unknown values' + ); + $this->assertNull( + PerfData::fromString('test=')->getUnit(), + 'Perfdata::getUnit does not return null for unknown values' + ); + $this->assertSame( + 'kW', + PerfData::fromString('test=-kW')->getUnit(), + 'Perfdata::getUnit does not return correct unit for invalid values' + ); + $this->assertSame( + 'kW', + PerfData::fromString('test=kW')->getUnit(), + 'Perfdata::getUnit does not return correct unit for invalid values' + ); + $this->assertNull( + PerfData::fromString('test=-')->getUnit(), + 'Perfdata::getUnit does not return null for unknown values' + ); + } + + /** + * @depends testWhetherFromStringParsesAGivenStringCorrectly + */ + public function testWhethergetWarningThresholdReturnsCorrectValues() + { + $zeroToTen = Perfdata::fromString('test=1;10')->getWarningThreshold(); + $this->assertSame( + 0.0, + $zeroToTen->getMin(), + 'Perfdata::getWarningThreshold does not return correct values' + ); + $this->assertSame( + 10.0, + $zeroToTen->getMax(), + 'Perfdata::getWarningThreshold does not return correct values' + ); + $tenToInfinity = Perfdata::fromString('test=1;10:')->getWarningThreshold(); + $this->assertSame( + 10.0, + $tenToInfinity->getMin(), + 'Perfdata::getWarningThreshold does not return correct values' + ); + $this->assertNull( + $tenToInfinity->getMax(), + 'Perfdata::getWarningThreshold does not return correct values' + ); + $infinityToTen = Perfdata::fromString('test=1;~:10')->getWarningThreshold(); + $this->assertNull( + $infinityToTen->getMin(), + 'Perfdata::getWarningThreshold does not return correct values' + ); + $this->assertSame( + 10.0, + $infinityToTen->getMax(), + 'Perfdata::getWarningThreshold does not return correct values' + ); + $tenToTwenty = Perfdata::fromString('test=1;10:20')->getWarningThreshold(); + $this->assertSame( + 10.0, + $tenToTwenty->getMin(), + 'Perfdata::getWarningThreshold does not return correct values' + ); + $this->assertSame( + 20.0, + $tenToTwenty->getMax(), + 'Perfdata::getWarningThreshold does not return correct values' + ); + $tenToTwentyInverted = Perfdata::fromString('test=1;@10:20')->getWarningThreshold(); + $this->assertTrue( + $tenToTwentyInverted->isInverted(), + 'Perfdata::getWarningThreshold does not return correct values' + ); + } + + /** + * @depends testWhetherFromStringParsesAGivenStringCorrectly + */ + public function testWhetherGetCriticalThresholdReturnsCorrectValues() + { + $zeroToTen = Perfdata::fromString('test=1;;10')->getCriticalThreshold(); + $this->assertSame( + 0.0, + $zeroToTen->getMin(), + 'Perfdata::getCriticalThreshold does not return correct values' + ); + $this->assertSame( + 10.0, + $zeroToTen->getMax(), + 'Perfdata::getCriticalThreshold does not return correct values' + ); + $tenToInfinity = Perfdata::fromString('test=1;;10:')->getCriticalThreshold(); + $this->assertSame( + 10.0, + $tenToInfinity->getMin(), + 'Perfdata::getCriticalThreshold does not return correct values' + ); + $this->assertNull( + $tenToInfinity->getMax(), + 'Perfdata::getCriticalThreshold does not return correct values' + ); + $infinityToTen = Perfdata::fromString('test=1;;~:10')->getCriticalThreshold(); + $this->assertNull( + $infinityToTen->getMin(), + 'Perfdata::getCriticalThreshold does not return correct values' + ); + $this->assertSame( + 10.0, + $infinityToTen->getMax(), + 'Perfdata::getCriticalThreshold does not return correct values' + ); + $tenToTwenty = Perfdata::fromString('test=1;;10:20')->getCriticalThreshold(); + $this->assertSame( + 10.0, + $tenToTwenty->getMin(), + 'Perfdata::getCriticalThreshold does not return correct values' + ); + $this->assertSame( + 20.0, + $tenToTwenty->getMax(), + 'Perfdata::getCriticalThreshold does not return correct values' + ); + $tenToTwentyInverted = Perfdata::fromString('test=1;;@10:20')->getCriticalThreshold(); + $this->assertTrue( + $tenToTwentyInverted->isInverted(), + 'Perfdata::getCriticalThreshold does not return correct values' + ); + } + + /** + * @depends testWhetherFromStringParsesAGivenStringCorrectly + */ + public function testWhetherGetMinimumValueReturnsCorrectValues() + { + $this->assertSame( + 1337.0, + Perfdata::fromString('test=1;;;1337')->getMinimumValue(), + 'Perfdata::getMinimumValue does not return correct values' + ); + $this->assertSame( + 1337.5, + Perfdata::fromString('test=1;;;1337.5')->getMinimumValue(), + 'Perfdata::getMinimumValue does not return correct values' + ); + } + + /** + * @depends testWhetherFromStringParsesAGivenStringCorrectly + */ + public function testWhetherGetMaximumValueReturnsCorrectValues() + { + $this->assertSame( + 1337.0, + Perfdata::fromString('test=1;;;;1337')->getMaximumValue(), + 'Perfdata::getMaximumValue does not return correct values' + ); + $this->assertSame( + 1337.5, + Perfdata::fromString('test=1;;;;1337.5')->getMaximumValue(), + 'Perfdata::getMaximumValue does not return correct values' + ); + } + + /** + * @depends testWhetherFromStringParsesAGivenStringCorrectly + */ + public function testWhetherMissingValuesAreProperlyHandled() + { + $perfdata = Perfdata::fromString('test=1;;3;5'); + $this->assertEmpty( + (string) $perfdata->getWarningThreshold(), + 'Perfdata objects do not correctly identify omitted warning tresholds' + ); + $this->assertNull( + $perfdata->getMaximumValue(), + 'Perfdata objects do not return null for missing maximum values' + ); + } + + /** + * @depends testWhetherGetValueReturnsValidValues + */ + public function testWhetherValuesAreIdentifiedAsNumber() + { + $this->assertTrue( + Perfdata::fromString('test=666')->isNumber(), + 'Perfdata objects do not identify ordinary digits as number' + ); + } + + /** + * @depends testWhetherGetValueReturnsValidValues + */ + public function testWhetherValuesAreIdentifiedAsSeconds() + { + $this->assertTrue( + Perfdata::fromString('test=666s')->isSeconds(), + 'Perfdata objects do not identify seconds as seconds' + ); + } + + /** + * @depends testWhetherGetValueReturnsValidValues + */ + public function testWhetherValuesAreIdentifiedAsPercentage() + { + $this->assertTrue( + Perfdata::fromString('test=66%')->isPercentage(), + 'Perfdata objects do not identify percentages as percentages' + ); + } + + /** + * @depends testWhetherValuesAreIdentifiedAsPercentage + */ + public function testWhetherMinAndMaxAreNotRequiredIfUnitIsInPercent() + { + $perfdata = Perfdata::fromString('test=1%'); + $this->assertSame( + 0.0, + $perfdata->getMinimumValue(), + 'Perfdata objects do not set minimum value to 0 if UOM is %' + ); + $this->assertSame( + 100.0, + $perfdata->getMaximumValue(), + 'Perfdata objects do not set maximum value to 100 if UOM is %' + ); + } + + /** + * @depends testWhetherGetValueReturnsValidValues + */ + public function testWhetherValuesAreIdentifiedAsBytes() + { + $this->assertTrue( + Perfdata::fromString('test=66666B')->isBytes(), + 'Perfdata objects do not identify bytes as bytes' + ); + } + + /** + * @depends testWhetherGetValueReturnsValidValues + */ + public function testWhetherValuesAreIdentifiedAsCounter() + { + $this->assertTrue( + Perfdata::fromString('test=123c')->isCounter(), + 'Perfdata objects do not identify counters as counters' + ); + } + + /** + * @depends testWhetherValuesAreIdentifiedAsPercentage + */ + public function testWhetherPercentagesAreHandledCorrectly() + { + $this->assertSame( + 66.0, + Perfdata::fromString('test=66%')->getPercentage(), + 'Perfdata objects do not correctly handle native percentages' + ); + $this->assertSame( + 50.0, + Perfdata::fromString('test=0;;;-250;250')->getPercentage(), + 'Perfdata objects do not correctly convert suitable values to percentages' + ); + $this->assertNull( + Perfdata::fromString('test=50')->getPercentage(), + 'Perfdata objects do return a percentage though their unit is not % and no maximum is given' + ); + $this->assertNull( + Perfdata::fromString('test=25;;;50;100')->getPercentage(), + 'Perfdata objects do return a percentage though their value is lower than it\'s allowed minimum' + ); + $this->assertNull( + Perfdata::fromString('test=25;;;0;')->getPercentage(), + 'Perfdata objects do not ignore empty max values when returning percentages' + ); + $this->assertNull( + Perfdata::fromString('test=25;;;0;0')->getPercentage(), + 'Perfdata objects do not ignore impossible min/max combinations when returning percentages' + ); + } + + public function testWhetherInvalidValueInPerfDataHandledCorrectly() + { + $p1 = Perfdata::fromString('test=2,0'); + $this->assertFalse($p1->isValid()); + $this->assertNull( + $p1->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertSame( + '2,0', + $p1->toArray()['value'] + ); + + $p2 = Perfdata::fromString('test=i am not a value'); + $this->assertFalse($p2->isValid()); + $this->assertNull( + $p2->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertSame( + 'i am not a value', + $p2->toArray()['value'] + ); + + $p3 = Perfdata::fromString('test='); + $this->assertFalse($p3->isValid()); + $this->assertNull( + $p3->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertSame( + '', + $p3->toArray()['value'] + ); + + $p4 = Perfdata::fromString('test=-kW'); + $this->assertFalse($p4->isValid()); + $this->assertNull( + $p4->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertSame( + '-kW', + $p4->toArray()['value'] + ); + + $p5 = Perfdata::fromString('test=kW'); + $this->assertFalse($p5->isValid()); + $this->assertNull( + $p5->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertSame( + 'kW', + $p5->toArray()['value'] + ); + + $p6 = Perfdata::fromString('test=-'); + $this->assertFalse($p6->isValid()); + $this->assertNull( + $p6->getValue(), + 'Perfdata::getValue does not return null for invalid values' + ); + $this->assertSame( + '-', + $p6->toArray()['value'] + ); + } + + public function testWhetherInvalidMinInPerfDataHandledCorrectly() + { + $p1 = Perfdata::fromString('test=1;;;2,0'); + $this->assertFalse($p1->isValid()); + $this->assertNull( + $p1->getMinimumValue(), + 'Perfdata::getMinimumValue does not return null for invalid min values' + ); + $this->assertSame( + '2,0', + $p1->toArray()['min'] + ); + + $p2 = Perfdata::fromString('test=1;;;foo'); + $this->assertFalse($p2->isValid()); + $this->assertNull( + $p2->getMinimumValue(), + 'Perfdata::getMinimumValue does not return null for invalid min values' + ); + $this->assertSame( + 'foo', + $p2->toArray()['min'] + ); + } + + public function testWhetherInvalidMaxInPerfDataHandledCorrectly() + { + $p1 = Perfdata::fromString('test=1;;;;2,0'); + $this->assertFalse($p1->isValid()); + $this->assertNull( + $p1->getMaximumValue(), + 'Perfdata::getMaximumValue does not return null for invalid max values' + ); + $this->assertSame( + '2,0', + $p1->toArray()['max'] + ); + + $p2 = Perfdata::fromString('test=1;;;;foo'); + $this->assertFalse($p2->isValid()); + $this->assertNull( + $p2->getMaximumValue(), + 'Perfdata::getMaximumValue does not return null for invalid max values' + ); + $this->assertSame( + 'foo', + $p2->toArray()['max'] + ); + } + + public function testWhetherInvalidWarningThresholdInPerfDataHandledCorrectly() + { + $p1 = Perfdata::fromString('test=1;2,0:'); + $this->assertFalse($p1->getWarningThreshold()->isValid()); + $this->assertFalse($p1->isValid()); + $this->assertSame( + '2,0:', + (string) $p1->getWarningThreshold() + ); + + $p2 = Perfdata::fromString('test=1;0:4,0'); + $this->assertFalse($p2->getWarningThreshold()->isValid()); + $this->assertFalse($p2->isValid()); + $this->assertSame( + '0:4,0', + (string) $p2->getWarningThreshold() + ); + + $p3 = Perfdata::fromString('test=1;foo'); + $this->assertFalse($p2->getWarningThreshold()->isValid()); + $this->assertFalse($p3->isValid()); + $this->assertSame( + 'foo', + (string) $p3->getWarningThreshold() + ); + + $p4 = Perfdata::fromString('test=1;10@'); + $this->assertFalse($p2->getWarningThreshold()->isValid()); + $this->assertFalse($p4->isValid()); + $this->assertSame( + '10@', + (string) $p4->getWarningThreshold() + ); + } + + public function testWhetherInvalidCriticalThresholdInPerfDataHandledCorrectly() + { + $p1 = Perfdata::fromString('test=1;;2,0:'); + $this->assertFalse($p1->getCriticalThreshold()->isValid()); + $this->assertFalse($p1->isValid()); + $this->assertSame( + '2,0:', + (string) $p1->getCriticalThreshold() + ); + + $p2 = Perfdata::fromString('test=1;;0:4,0'); + $this->assertFalse($p2->getCriticalThreshold()->isValid()); + $this->assertFalse($p2->isValid()); + $this->assertSame( + '0:4,0', + (string) $p2->getCriticalThreshold() + ); + + $p3 = Perfdata::fromString('test=1;;foo'); + $this->assertFalse($p2->getCriticalThreshold()->isValid()); + $this->assertFalse($p3->isValid()); + $this->assertSame( + 'foo', + (string) $p3->getCriticalThreshold() + ); + + $p4 = Perfdata::fromString('test=1;;10@'); + $this->assertFalse($p2->getCriticalThreshold()->isValid()); + $this->assertFalse($p4->isValid()); + $this->assertSame( + '10@', + (string) $p4->getCriticalThreshold() + ); + } +} diff --git a/test/php/library/Icingadb/Util/ThresholdRangeTest.php b/test/php/library/Icingadb/Util/ThresholdRangeTest.php new file mode 100644 index 0000000..b191e88 --- /dev/null +++ b/test/php/library/Icingadb/Util/ThresholdRangeTest.php @@ -0,0 +1,343 @@ +<?php + +/* Icinga DB Web | (c) 2023 Icinga GmbH | GPLv2 */ + +namespace Tests\Icinga\Module\Icingadb\Util; + +use Icinga\Module\Icingadb\Util\ThresholdRange; +use PHPUnit\Framework\TestCase; + +class ThresholdRangeTest extends TestCase +{ + public function testFromStringProperlyParsesDoubleExclusiveRanges() + { + $outside0And10 = ThresholdRange::fromString('10'); + $this->assertSame( + 0.0, + $outside0And10->getMin(), + 'ThresholdRange::fromString() does not identify zero as default minimum for double exclusive ranges' + ); + $this->assertSame( + 10.0, + $outside0And10->getMax(), + 'ThresholdRange::fromString() does not identify ten as explicit maximum for double exclusive ranges' + ); + $this->assertFalse( + $outside0And10->isInverted(), + 'ThresholdRange::fromString() identifies double exclusive ranges as inclusive' + ); + + $outside10And20 = ThresholdRange::fromString('10:20'); + $this->assertSame( + 10.0, + $outside10And20->getMin(), + 'ThresholdRange::fromString() does not identify ten as explicit minimum for double exclusive ranges' + ); + $this->assertSame( + 20.0, + $outside10And20->getMax(), + 'ThresholdRange::fromString() does not identify twenty as explicit maximum for double exclusive ranges' + ); + $this->assertFalse( + $outside10And20->isInverted(), + 'ThresholdRange::fromString() identifies double exclusive ranges as inclusive' + ); + } + + /** + * @depends testFromStringProperlyParsesDoubleExclusiveRanges + */ + public function testContainsCorrectlyEvaluatesDoubleExclusiveRanges() + { + $outside0And10 = ThresholdRange::fromString('10'); + $this->assertFalse( + $outside0And10->contains(-1), + 'ThresholdRange::contains() identifies negative values as greater than or equal to zero' + ); + $this->assertFalse( + $outside0And10->contains(11), + 'ThresholdRange::contains() identifies eleven as smaller than or equal to ten' + ); + $this->assertTrue( + $outside0And10->contains(10), + 'ThresholdRange::contains() identifies 10 as outside the range 0..10' + ); + + $outside10And20 = ThresholdRange::fromString('10:20'); + $this->assertFalse( + $outside10And20->contains(9), + 'ThresholdRange::contains() identifies nine as greater than or equal to 10' + ); + $this->assertFalse( + $outside10And20->contains(21), + 'ThresholdRange::contains() identifies twenty-one as smaller than or equal to twenty' + ); + $this->assertTrue( + $outside10And20->contains(20), + 'ThresholdRange::contains() identifies 20 as outside the range 10..20' + ); + } + + public function testFromStringProperlyParsesSingleExclusiveRanges() + { + $smallerThan10 = ThresholdRange::fromString('10:'); + $this->assertSame( + 10.0, + $smallerThan10->getMin(), + 'ThresholdRange::fromString() does not identify ten as explicit minimum for single exclusive ranges' + ); + $this->assertNull( + $smallerThan10->getMax(), + 'ThresholdRange::fromString() does not identify infinity as default maximum for single exclusive ranges' + ); + $this->assertFalse( + $smallerThan10->isInverted(), + 'ThresholdRange::fromString() identifies single exclusive ranges as inclusive' + ); + + $greaterThan10 = ThresholdRange::fromString('~:10'); + $this->assertNull( + $greaterThan10->getMin(), + 'ThresholdRange::fromString() does not identify infinity as explicit minimum for single exclusive ranges' + ); + $this->assertSame( + 10.0, + $greaterThan10->getMax(), + 'ThresholdRange::fromString() does not identify ten as explicit maximum for single exclusive ranges' + ); + $this->assertFalse( + $greaterThan10->isInverted(), + 'ThresholdRange::fromString() identifies single exclusive ranges as inclusive' + ); + } + + /** + * @depends testFromStringProperlyParsesSingleExclusiveRanges + */ + public function testContainsCorrectlyEvaluatesSingleExclusiveRanges() + { + $smallerThan10 = ThresholdRange::fromString('10:'); + $this->assertFalse( + $smallerThan10->contains(9), + 'ThresholdRange::contains() identifies nine as greater than or equal to ten' + ); + $this->assertTrue( + $smallerThan10->contains(PHP_INT_MAX), + 'ThresholdRange::contains() identifies infinity as outside the range 10..~' + ); + + $greaterThan10 = ThresholdRange::fromString('~:10'); + $this->assertFalse( + $greaterThan10->contains(11), + 'ThresholdRange::contains() identifies eleven as smaller than or equal to ten' + ); + $this->assertTrue( + $greaterThan10->contains(~PHP_INT_MAX), + 'ThresholdRange::contains() identifies negative infinity as outside the range ~..10' + ); + } + + public function testFromStringProperlyParsesInclusiveRanges() + { + $inside0And10 = ThresholdRange::fromString('@10'); + $this->assertSame( + 0.0, + $inside0And10->getMin(), + 'ThresholdRange::fromString() does not identify zero as default minimum for inclusive ranges' + ); + $this->assertSame( + 10.0, + $inside0And10->getMax(), + 'ThresholdRange::fromString() does not identify ten as explicit maximum for inclusive ranges' + ); + $this->assertTrue( + $inside0And10->isInverted(), + 'ThresholdRange::fromString() identifies inclusive ranges as double exclusive' + ); + + $inside10And20 = ThresholdRange::fromString('@10:20'); + $this->assertSame( + 10.0, + $inside10And20->getMin(), + 'ThresholdRange::fromString() does not identify ten as explicit minimum for inclusive ranges' + ); + $this->assertSame( + 20.0, + $inside10And20->getMax(), + 'ThresholdRange::fromString() does not identify twenty as explicit maximum for inclusive ranges' + ); + $this->assertTrue( + $inside10And20->isInverted(), + 'ThresholdRange::fromString() identifies inclusive ranges as double exclusive' + ); + + $greaterThan10 = ThresholdRange::fromString('@10:'); + $this->assertSame( + 10.0, + $greaterThan10->getMin(), + 'ThresholdRange::fromString() does not identify ten as explicit minimum for inclusive ranges' + ); + $this->assertNull( + $greaterThan10->getMax(), + 'ThresholdRange::fromString() does not identify infinity as default maximum for inclusive ranges' + ); + $this->assertTrue( + $greaterThan10->isInverted(), + 'ThresholdRange::fromString() identifies inclusive ranges as single exclusive' + ); + + $smallerThan10 = ThresholdRange::fromString('@~:10'); + $this->assertNull( + $smallerThan10->getMin(), + 'ThresholdRange::fromString() does not identify infinity as explicit minimum for inclusive ranges' + ); + $this->assertSame( + 10.0, + $smallerThan10->getMax(), + 'ThresholdRange::fromString() does not identify ten as explicit maximum for inclusive ranges' + ); + $this->assertTrue( + $smallerThan10->isInverted(), + 'ThresholdRange::fromString() identifies inclusive ranges as single exclusive' + ); + } + + /** + * @depends testFromStringProperlyParsesInclusiveRanges + */ + public function testContainsCorrectlyEvaluatesInclusiveRanges() + { + $inside0And10 = ThresholdRange::fromString('@10'); + $this->assertFalse( + $inside0And10->contains(10), + 'ThresholdRange::contains() identifies ten as greater than ten' + ); + $this->assertTrue( + $inside0And10->contains(11), + 'ThresholdRange::contains() identifies eleven as smaller than or equal to ten' + ); + $this->assertTrue( + $inside0And10->contains(-1), + 'ThresholdRange::contains() identifies negative values as greater than or equal to zero' + ); + + $inside10And20 = ThresholdRange::fromString('@10:20'); + $this->assertFalse( + $inside10And20->contains(20), + 'ThresholdRange::contains() identifies twenty as greater than twenty' + ); + $this->assertTrue( + $inside10And20->contains(21), + 'ThresholdRange::contains() identifies twenty-one as smaller than or equal to twenty' + ); + $this->assertTrue( + $inside10And20->contains(9), + 'ThresholdRange::contains() identifies nine as greater than or equal to ten' + ); + + $greaterThan10 = ThresholdRange::fromString('@10:'); + $this->assertFalse( + $greaterThan10->contains(PHP_INT_MAX), + 'ThresholdRange::contains() identifies infinity as smaller than ten' + ); + $this->assertTrue( + $greaterThan10->contains(9), + 'ThresholdRange::contains() identifies nine as greater than or equal to ten' + ); + + $smallerThan10 = ThresholdRange::fromString('@~:10'); + $this->assertFalse( + $smallerThan10->contains(~PHP_INT_MAX), + 'ThresholdRange::contains() identifies negative infinity as greater than ten' + ); + $this->assertTrue( + $smallerThan10->contains(11), + 'ThresholdRange::contains() identifies eleven as smaller than or equal to ten' + ); + } + + public function testFromStringProperlyParsesEmptyThresholds() + { + $emptyThreshold = ThresholdRange::fromString(''); + $this->assertNull( + $emptyThreshold->getMin(), + 'ThresholdRange::fromString() does not identify negative infinity as implicit minimum for empty strings' + ); + $this->assertNull( + $emptyThreshold->getMax(), + 'ThresholdRange::fromString() does not identify infinity as implicit maximum for empty strings' + ); + $this->assertFalse( + $emptyThreshold->isInverted(), + 'ThresholdRange::fromString() identifies empty strings as inclusive ranges rather than exclusive' + ); + } + + /** + * @depends testFromStringProperlyParsesEmptyThresholds + */ + public function testContainsEvaluatesEverythingToTrueForEmptyThresholds() + { + $emptyThreshold = ThresholdRange::fromString(''); + $this->assertTrue( + $emptyThreshold->contains(0), + 'ThresholdRange::contains() does not identify zero as valid without any threshold' + ); + $this->assertTrue( + $emptyThreshold->contains(10), + 'ThresholdRange::contains() does not identify ten as valid without any threshold' + ); + $this->assertTrue( + $emptyThreshold->contains(PHP_INT_MAX), + 'ThresholdRange::contains() does not identify infinity as valid without any threshold' + ); + $this->assertTrue( + $emptyThreshold->contains(~PHP_INT_MAX), + 'ThresholdRange::contains() does not identify negative infinity as valid without any threshold' + ); + } + + public function testInvalidThresholdNotationsAreRenderedAsIs() + { + $this->assertSame( + ':', + (string) ThresholdRange::fromString(':') + ); + $this->assertSame( + '~:', + (string) ThresholdRange::fromString('~:') + ); + $this->assertSame( + '20:10', + (string) ThresholdRange::fromString('20:10') + ); + $this->assertSame( + '10@', + (string) ThresholdRange::fromString('10@') + ); + $this->assertSame( + 'foo', + (string) ThresholdRange::fromString('foo') + ); + $this->assertSame( + '4,4:2,2', + (string) ThresholdRange::fromString('4,4:2,2') + ); + } + + public function testInvalidThresholdNotationsConsideredInValid() + { + $this->assertFalse( + ThresholdRange::fromString('10@')->isValid(), + 'Invalid threshold notation 10@ considered as valid' + ); + $this->assertFalse( + ThresholdRange::fromString('foo')->isValid(), + 'Invalid threshold notation foo considered as valid' + ); + $this->assertFalse( + ThresholdRange::fromString('4,4:2,2')->isValid(), + 'Invalid threshold notation 4,4:2,2 considered as valid' + ); + } +} |