Merge branch 'bugfix/failsafe-perfdata-parser-5973'

fixes #5973
This commit is contained in:
Johannes Meyer 2014-05-05 16:18:11 +02:00
commit dd3e406052
11 changed files with 897 additions and 302 deletions

View File

@ -79,7 +79,7 @@ class Cli extends ApplicationBootstrap
array(
'enable' => true,
'level' => Logger::$INFO,
'type' => 'stream',
'type' => 'file',
'target' => 'php://stderr'
)
)

View File

@ -50,6 +50,9 @@ class Format
);
protected static $byteBase = array(1024, 1000);
protected static $secondPrefix = array('s', 'ms', 'µs', 'ns', 'ps', 'fs', 'as');
protected static $secondBase = 1000;
public static function getInstance()
{
if (self::$instance === null) {
@ -76,6 +79,20 @@ class Format
);
}
public static function seconds($value)
{
if ($value < 60) {
return self::formatForUnits($value, self::$secondPrefix, self::$secondBase);
} elseif ($value < 3600) {
return sprintf('0.2f m', $value / 60);
} elseif ($value < 86400) {
return sprintf('0.2f h', $value / 3600);
}
// TODO: Do we need weeks, months and years?
return sprintf('0.2f d', $value / 86400);
}
public static function duration($duration)
{
if ($duration === null || $duration === false) {
@ -148,7 +165,7 @@ class Format
'%s%0.2f %s',
$sign,
$result,
$units[$pow]
$units[abs($pow)]
);
}

View File

@ -263,9 +263,9 @@ class ListCommand extends Command
try {
$pset = PerfdataSet::fromString($row->service_perfdata);
$perfs = array();
foreach ($pset->getAll() as $perfName => $p) {
foreach ($pset as $perfName => $p) {
if ($percent = $p->getPercentage()) {
if ($percent < 0 || $percent > 300) {
if ($percent < 0 || $percent > 100) {
continue;
}
$perfs[] = ' '

View File

@ -1,90 +1,82 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Module\Monitoring\Plugin\PerfdataSet;
use Icinga\Util\Format;
use Icinga\Web\Widget\Chart\InlinePie;
use Icinga\Module\Monitoring\Plugin\Perfdata;
use Icinga\Module\Monitoring\Plugin\PerfdataSet;
class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
{
public function perfdata($perfdata, $compact = false, $float = 'right')
public function perfdata($perfdataStr, $compact = false)
{
if (empty($perfdata)) {
return '';
}
if ($float) {
$float = ' float: ' . $float . ';';
} else {
$float = '';
}
$pset = PerfdataSet::fromString($perfdata);
$ps = $pset->getAll();
$perfdata = preg_replace_callback('~\'([^\']+)\'~', function($match) { return str_replace(' ', '\'', $match[1]); }, $perfdata);
$parts = preg_split('~\s+~', $perfdata, -1, PREG_SPLIT_NO_EMPTY);
$table = array();
$result = '';
if ($compact === true) {
$compact = 5;
}
if ($compact && count($parts) > $compact) {
$parts = array_slice($parts, 0, $compact);
}
foreach ($parts as $part) {
if (strpos($part, '=') === false) continue;
list($name, $vals) = preg_split('~=~', $part, 2);
$name = str_replace("'", ' ', $name);
$parts = preg_split('~;~', $vals, 5);
while (count($parts) < 5) $parts[] = null;
list($val, $warn, $crit, $min, $max) = $parts;
$unit = '';
if (preg_match('~^([\d+\.]+)([^\d]+)$~', $val, $m)) {
$unit = $m[2];
$val = $m[1];
} else {
$table = array();
$pset = array_slice(PerfdataSet::fromString($perfdataStr)->asArray(), 0, ($compact ? 5 : null));
foreach ($pset as $label => $perfdata) {
if (!$perfdata->isPercentage() && $perfdata->getMaximumValue() === null) {
continue;
}
if ($unit == 'c') continue; // Counter pie graphs are not useful
if ($compact && $val < 0.0001) continue;
if ($unit == '%') {
if (! $min ) $min = 0;
if (! $max) $max = 100;
} else {
if (! $max && $crit > 0) $max = $crit;
//return '';
}
if (! $max) continue;
$green = 0;
$orange = 0;
$red = 0;
$gray = $max - $val;
if ($val < $warn) $green = $val;
elseif ($val < $crit) $orange = $val;
else $red = $val;
$inlinePie = new InlinePie(array($green, $orange, $red, $gray));
$pieChart = new InlinePie($this->calculatePieChartData($perfdata));
if ($compact) {
$inlinePie->setTitle(htmlspecialchars($name) . ': ' . htmlspecialchars($ps[$name]->getFormattedValue()));
$inlinePie->setStyle('float: right;');
$result .= $inlinePie->render();
$pieChart->setTitle(
htmlspecialchars($label) . ': ' . htmlspecialchars($this->formatPerfdataValue($perfdata))
);
$pieChart->setStyle('float: right;');
$result .= $pieChart->render();
} else {
$inlinePie->setTitle(htmlspecialchars($name));
$inlinePie->setStyle('float: left; margin: 0.2em 0.5em 0.2em 0;');
$table[] = '<tr><th>' . $inlinePie->render()
. htmlspecialchars($name)
$pieChart->setTitle(htmlspecialchars($label));
$pieChart->setStyle('float: left; margin: 0.2em 0.5em 0.2em 0;');
$table[] = '<tr><th>' . $pieChart->render()
. htmlspecialchars($label)
. '</th><td>'
. htmlspecialchars($ps[$name]->getFormattedValue()) .
. htmlspecialchars($this->formatPerfdataValue($perfdata)) .
'</td></tr>';
}
}
if ($result == '' && ! $compact) {
$result = $perfdata;
// TODO: What if we have both? And should we trust sprintf-style placeholders in perfdata titles?
if (empty($table)) {
return $compact ? $result : $perfdataStr;
} else {
return '<table class="perfdata">' . implode("\n", $table) . '</table>';
}
if (! empty($table)) {
// TODO: What if we have both? And should we trust sprintf-style placeholders in perfdata titles?
$result = '<table class="perfdata">' . implode("\n", $table) . '</table>';
}
protected function calculatePieChartData(Perfdata $perfdata)
{
$rawValue = $perfdata->getValue();
$minValue = $perfdata->getMinimumValue() !== null ? $perfdata->getMinimumValue() : 0;
$maxValue = $perfdata->getMaximumValue();
$usedValue = ($rawValue - $minValue);
$unusedValue = ($maxValue - $minValue) - $usedValue;
$gray = $unusedValue;
$green = $orange = $red = 0;
// TODO(#6122): Add proper treshold parsing.
if ($perfdata->getCriticalTreshold() && $perfdata->getValue() > $perfdata->getCriticalTreshold()) {
$red = $usedValue;
} elseif ($perfdata->getWarningTreshold() && $perfdata->getValue() > $perfdata->getWarningTreshold()) {
$orange = $usedValue;
} else {
$green = $usedValue;
}
return $result;
return array($green, $orange, $red, $gray);
}
protected function formatPerfdataValue(Perfdata $perfdata)
{
if ($perfdata->isBytes()) {
return Format::bytes($perfdata->getValue());
} elseif ($perfdata->isSeconds()) {
return Format::seconds($perfdata->getValue());
} elseif ($perfdata->isPercentage()) {
return $perfdata->getValue() . '%';
}
return $perfdata->getValue();
}
}

View File

@ -1,223 +1,280 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Plugin;
use Icinga\Exception\ProgrammingError;
class Perfdata
{
const COUNTER = 0x01;
const PERCENT = 0x02;
const BYTES = 0x04;
const SECONDS = 0x08;
protected $byte_map;
protected $min;
protected $max;
protected $warn;
protected $crit;
protected $val;
/**
* The performance data value being parsed
*
* @var string
*/
protected $perfdataValue;
/**
* Unit of measurement (UOM)
*
* @var string
*/
protected $unit;
public function getFormattedValue()
{
switch ($this->unit) {
case self::BYTES:
return $this->formatBytes() . ' von ' . $this->formatBytes($this->max);
break;
case self::SECONDS:
return $this->formatSeconds();
break;
case self::PERCENT:
return number_format($this->val, 2, ',', '.') . '%';
break;
default:
return $this->val;
}
}
/**
* The value
*
* @var float
*/
protected $value;
public function hasMax()
{
return $this->max !== null && $this->max > 0;
}
/**
* The minimum value
*
* @var float
*/
protected $minValue;
public function getPercentage()
{
if ($this->unit === self::PERCENT) {
return $this->val;
}
if ($this->hasMax()) {
return $this->val / $this->max * 100;
}
return false;
}
/**
* The maximum value
*
* @var float
*/
protected $maxValue;
public function getValue()
{
return $this->val;
}
/**
* The WARNING treshold
*
* @var string
*/
protected $warningTreshold;
protected function formatBytes($val = null)
{
$steps = array(
1 => 'Byte',
1024 => 'KByte',
1024 * 1024 => 'MByte',
1024 * 1024 * 1024 => 'GByte',
1024 * 1024 * 1024 * 1024 => 'TByte'
);
return $this->formatSpecial($steps, 1, $val);
}
/**
* The CRITICAL treshold
*
* @var string
*/
protected $criticalTreshold;
protected function formatSeconds()
/**
* Create a new Perfdata object based on the given performance data value
*
* @param string $perfdataValue The value to parse
*/
protected function __construct($perfdataValue)
{
$steps = array(
1 => 'us',
1000 => 'ms',
10000000 => 's',
);
return $this->formatSpecial($steps, 1000000, $this->val);
}
$this->perfdataValue = $perfdataValue;
$this->parse();
protected function formatSpecial($steps, $multi = 1, $val = null)
{
if ($val === null) {
$val = abs($this->val);
} else {
$val = abs($val);
}
// TODO: Check this, prefix fails if $val is given
if ($this->val < 0) {
$prefix = '-';
} else {
$prefix = '';
}
$val *= $multi;
$step = 1;
foreach (array_keys($steps) as $key) {
if ($key > $val * 1) {
break;
if ($this->unit === '%') {
if ($this->minValue === null) {
$this->minValue = 0.0;
}
$step = $key;
}
if ($step <= 0) $step = 1;
return $prefix
. number_format($val / $step, 1, ',', '.')
. ' '
. $steps[$step];
}
protected function __construct(& $perfdata)
{
$this->byte_map = array(
'b' => 1,
'kb' => 1024,
'mb' => 1024 * 1024,
'gb' => 1024 * 1024 * 1024,
'tb' => 1024 * 1024 * 1024 * 1024
);
// UGLY, fixes floats using comma:
$perfdata = preg_replace('~\,~', '.', $perfdata);
$parts = preg_split('~;~', $perfdata, 5);
while (count($parts) < 5) {
$parts[] = null;
}
list(
$this->val,
$this->warn,
$this->crit,
$this->min,
$this->max
) = $parts;
// TODO: check numbers!
$unit = null;
if (! preg_match('~^(\-?[\d+\.]+(?:E\-?\d+)?)([^\d]+)?$~', $this->val, $m)) {
return $perfdata;
// Numbers with an exponential base will be rendered invalid using the regex above
// throw new \Exception('Got invalid perfdata: ' . $perfdata);
}
$this->val = $m[1];
if (isset($m[2])) {
$unit = strtolower($m[2]);
}
if ($unit === 'c') {
$this->unit = self::COUNTER;
}
if ($unit === '%') {
if (! is_numeric($this->min)) {
$this->min = 0;
}
if (! is_numeric($this->max)) {
$this->max = 100;
}
$this->unit = self::PERCENT;
} else {
if (! is_numeric($this->max) && $this->crit > 0) {
$this->max = $this->crit;
}
}
if (array_key_exists($unit, $this->byte_map)) {
$this->unit = self::BYTES;
$this->val = $this->val * $this->byte_map[$unit];
$this->min = $this->min * $this->byte_map[$unit];
$this->max = $this->max * $this->byte_map[$unit];
}
if ($unit === 's') {
$this->unit = self::SECONDS;
}
if ($unit === 'ms') {
$this->unit = self::SECONDS;
$this->val = $this->val / 1000;
}
if ($unit === '%') {
if (! is_numeric($this->min)) {
$this->min = 0;
}
if (! is_numeric($this->max)) {
$this->max = 100;
}
} else {
if (! is_numeric($this->max) && $this->crit > 0) {
$this->max = $this->crit;
if ($this->maxValue === null) {
$this->maxValue = 100.0;
}
}
}
/**
* Return a new Perfdata object based on the given performance data value
*
* @param string $perfdataValue The value to parse
*
* @return Perfdata
*
* @throws ProgrammingError In case the given performance data value has no content
*/
public static function fromString($perfdataValue)
{
if (empty($perfdataValue)) {
throw new ProgrammingError('Perfdata::fromString expects a string with content');
}
return new static($perfdataValue);
}
/**
* Return whether this performance data value is a number
*
* @return bool True in case it's a number, otherwise False
*/
public function isNumber()
{
return $this->unit === null;
}
/**
* Return whether this performance data value are seconds
*
* @return bool True in case it's seconds, otherwise False
*/
public function isSeconds()
{
return in_array($this->unit, array('s', 'ms', 'us'));
}
/**
* Return whether this performance data value is in percentage
*
* @return bool True in case it's in percentage, otherwise False
*/
public function isPercentage()
{
return $this->unit === '%';
}
/**
* Return whether this performance data value is in bytes
*
* @return bool True in case it's in bytes, otherwise False
*/
public function isBytes()
{
return in_array($this->unit, array('b', 'kb', 'mb', 'gb', 'tb'));
}
/**
* Return whether this performance data value is a counter
*
* @return bool True in case it's a counter, otherwise False
*/
public function isCounter()
{
return $this->unit === self::COUNTER;
return $this->unit === 'c';
}
public static function fromString(& $perfdata)
/**
* Return the value or null if it is unknown (U)
*
* @return null|float
*/
public function getValue()
{
$pdat = new Perfdata($perfdata);
return $pdat;
return $this->value;
}
protected function normalizeNumber($num)
/**
* Return the value as percentage (0-100)
*
* @return null|float
*/
public function getPercentage()
{
return $num;
// Bullshit, still TODO
/*
$dot = strpos($num, '.');
$comma = strpos($num, ',');
if ($dot === false) {
// No dot...
if ($comma === false) {
// ...and no comma, it's an integer:
return (int) $num;
} else {
// just a comma
}
} else {
if ($comma === false) {
if ($this->isPercentage()) {
return $this->value;
}
if ($this->maxValue !== null) {
$minValue = $this->minValue !== null ? $this->minValue : 0;
if ($this->value > $minValue) {
return (($this->value - $minValue) / ($this->maxValue - $minValue)) * 100;
}
}
}
/**
* Return this value's warning treshold or null if it is not available
*
* @return null|string
*/
public function getWarningTreshold()
{
return $this->warningTreshold;
}
/**
* Return this value's critical treshold or null if it is not available
*
* @return null|string
*/
public function getCriticalTreshold()
{
return $this->criticalTreshold;
}
/**
* Return the minimum value or null if it is not available
*
* @return null|float
*/
public function getMinimumValue()
{
return $this->minValue;
}
/**
* Return the maximum value or null if it is not available
*
* @return null|float
*/
public function getMaximumValue()
{
return $this->maxValue;
}
/**
* Parse the current performance data value
*
* @todo Handle optional min/max if UOM == %
*/
protected function parse()
{
$parts = explode(';', $this->perfdataValue);
$matches = array();
if (preg_match('@^(\d+(\.\d+)?)([a-zA-Z%]{1,2})$@', $parts[0], $matches)) {
$this->unit = strtolower($matches[3]);
$this->value = self::convert($matches[1], $this->unit);
} else {
$this->value = self::convert($parts[0]);
}
switch (count($parts))
{
case 5:
$this->maxValue = self::convert($parts[4], $this->unit);
case 4:
$this->minValue = self::convert($parts[3], $this->unit);
case 3:
// TODO(#6123): Tresholds have the same UOM and need to be converted as well!
$this->criticalTreshold = trim($parts[2]) ? trim($parts[2]) : null;
case 2:
// TODO(#6123): Tresholds have the same UOM and need to be converted as well!
$this->warningTreshold = trim($parts[1]) ? trim($parts[1]) : null;
}
}
/**
* Return the given value converted to its smallest supported representation
*
* @param string $value The value to convert
* @param string $fromUnit The unit the value currently represents
*
* @return null|float Null in case the value is not a number
*/
protected static function convert($value, $fromUnit = null)
{
if (is_numeric($value)) {
switch ($fromUnit)
{
case 'us':
return $value / pow(10, 6);
case 'ms':
return $value / pow(10, 3);
case 'tb':
return floatval($value) * pow(2, 40);
case 'gb':
return floatval($value) * pow(2, 30);
case 'mb':
return floatval($value) * pow(2, 20);
case 'kb':
return floatval($value) * pow(2, 10);
default:
return (float) $value;
}
}
*/
}
}

View File

@ -1,68 +1,144 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Monitoring\Plugin;
class PerfdataSet
{
protected $ptr;
protected $pos = 0;
protected $len;
protected $perfdata;
use ArrayIterator;
use IteratorAggregate;
protected function __construct($perfdata)
class PerfdataSet implements IteratorAggregate
{
/**
* The performance data being parsed
*
* @var string
*/
protected $perfdataStr;
/**
* The current parsing position
*
* @var int
*/
protected $parserPos = 0;
/**
* A list of Perfdata objects
*
* @var array
*/
protected $perfdata = array();
/**
* Create a new set of performance data
*
* @param string $perfdataStr A space separated list of label/value pairs
*/
protected function __construct($perfdataStr)
{
if (empty($perfdata)) return;
$this->ptr = & $perfdata;
$this->len = strlen($this->ptr);
while ($this->pos < $this->len) {
$label = $this->readLabel();
$perf = $this->readUntil(' ');
if (empty($perf)) continue;
$this->perfdata[$label] = Perfdata::fromString($perf);
if (($perfdataStr = trim($perfdataStr)) !== '') {
$this->perfdataStr = $perfdataStr;
$this->parse();
}
}
public static function fromString(& $perfdata)
/**
* Return a iterator for this set of performance data
*
* @return ArrayIterator
*/
public function getIterator()
{
$pset = new PerfdataSet($perfdata);
return $pset;
return new ArrayIterator($this->asArray());
}
public function getAll()
/**
* Return a new set of performance data
*
* @param string $perfdataStr A space separated list of label/value pairs
*
* @return PerfdataSet
*/
public static function fromString($perfdataStr)
{
return $this->perfdata === null ? array() : $this->perfdata;
return new static($perfdataStr);
}
/**
* Return this set of performance data as array
*
* @return array
*/
public function asArray()
{
return $this->perfdata;
}
/**
* Parse the current performance data
*/
protected function parse()
{
while ($this->parserPos < strlen($this->perfdataStr)) {
$label = trim($this->readLabel());
$value = trim($this->readUntil(' '));
if ($label && $value) {
$this->perfdata[$label] = Perfdata::fromString($value);
}
}
}
/**
* Return the next label found in the performance data
*
* @return string The label found
*/
protected function readLabel()
{
$this->skipSpaces();
if (in_array($this->ptr[$this->pos], array('"', "'"))) {
$this->pos++;
$label = $this->readUntil($this->ptr[$this->pos - 1]);
$this->pos++; // Skip ' or "
$skip = $this->readUntil('=');
$this->pos++;
if (in_array($this->perfdataStr[$this->parserPos], array('"', "'"))) {
$quoteChar = $this->perfdataStr[$this->parserPos++];
$label = $this->readUntil('=');
$this->parserPos++;
if (($closingPos = strpos($label, $quoteChar)) > 0) {
$label = substr($label, 0, $closingPos);
}
} else {
$label = $this->readUntil('=');
$this->pos++;
$this->parserPos++;
}
$this->skipSpaces();
return trim($label);
return $label;
}
protected function readUntil($stop_char)
/**
* Return all characters between the current parser position and the given character
*
* @param string $stopChar The character on which to stop
*
* @return string
*/
protected function readUntil($stopChar)
{
$start = $this->pos;
while ($this->pos < $this->len && $this->ptr[$this->pos] !== $stop_char) {
$this->pos++;
$start = $this->parserPos;
while ($this->parserPos < strlen($this->perfdataStr) && $this->perfdataStr[$this->parserPos] !== $stopChar) {
$this->parserPos++;
}
return substr($this->ptr, $start, $this->pos - $start);
return substr($this->perfdataStr, $start, $this->parserPos - $start);
}
/**
* Advance the parser position to the next non-whitespace character
*/
protected function skipSpaces()
{
while ($this->pos < $this->len && $this->ptr[$this->pos] === ' ') {
$this->pos++;
while ($this->parserPos < strlen($this->perfdataStr) && $this->perfdataStr[$this->parserPos] === ' ') {
$this->parserPos++;
}
}
}

View File

@ -2,7 +2,7 @@
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Tests\Icinga\Module\Monitoring\Library\Filter\Type;
namespace Tests\Icinga\Module\Monitoring\Filter\Type;
use Icinga\Module\Monitoring\Filter\Type\StatusFilter;
use Icinga\Filter\Type\TimeRangeSpecifier;

View File

@ -2,7 +2,7 @@
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Tests\Icinga\Module\Monitoring\Library\Filter;
namespace Tests\Icinga\Module\Monitoring\Filter;
use \Mockery;
use Icinga\Module\Monitoring\Filter\Type\StatusFilter;

View File

@ -0,0 +1,101 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Tests\Icinga\Module\Monitoring\Plugin;
use Icinga\Test\BaseTestCase;
use Icinga\Module\Monitoring\Plugin\PerfdataSet;
class PerfdataSetWithPublicData extends PerfdataSet
{
public $perfdata = array();
}
class PerfdataSetTest extends BaseTestCase
{
public function testWhetherValidSimplePerfdataLabelsAreProperlyParsed()
{
$pset = PerfdataSetWithPublicData::fromString('key1=val1 key2=val2 key3 =val3');
$this->assertArrayHasKey(
'key1',
$pset->perfdata,
'PerfdataSet does not correctly parse valid simple labels'
);
$this->assertArrayHasKey(
'key2',
$pset->perfdata,
'PerfdataSet does not correctly parse valid simple labels'
);
$this->assertArrayHasKey(
'key3',
$pset->perfdata,
'PerfdataSet does not correctly parse valid simple labels'
);
}
public function testWhetherNonQuotedPerfdataLablesWithSpacesAreProperlyParsed()
{
$pset = PerfdataSetWithPublicData::fromString('key 1=val1 key 1 + 1=val2');
$this->assertArrayHasKey(
'key 1',
$pset->perfdata,
'PerfdataSet does not correctly parse non quoted labels with spaces'
);
$this->assertArrayHasKey(
'key 1 + 1',
$pset->perfdata,
'PerfdataSet does not correctly parse non quoted labels with spaces'
);
}
public function testWhetherValidQuotedPerfdataLabelsAreProperlyParsed()
{
$pset = PerfdataSetWithPublicData::fromString('\'key 1\'=val1 "key 2"=val2');
$this->assertArrayHasKey(
'key 1',
$pset->perfdata,
'PerfdataSet does not correctly parse valid quoted labels'
);
$this->assertArrayHasKey(
'key 2',
$pset->perfdata,
'PerfdataSet does not correctly parse valid quoted labels'
);
}
public function testWhetherInvalidQuotedPerfdataLabelsAreProperlyParsed()
{
$pset = PerfdataSetWithPublicData::fromString('\'key 1=val1 key 2"=val2');
$this->assertArrayHasKey(
'key 1',
$pset->perfdata,
'PerfdataSet does not correctly parse invalid quoted labels'
);
$this->assertArrayHasKey(
'key 2"',
$pset->perfdata,
'PerfdataSet does not correctly parse invalid quoted labels'
);
}
/**
* @depends testWhetherValidSimplePerfdataLabelsAreProperlyParsed
*/
public function testWhetherAPerfdataSetIsIterable()
{
$pset = PerfdataSet::fromString('key=value');
foreach ($pset as $label => $value) {
$this->assertEquals('key', $label);
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');
}
}

View File

@ -0,0 +1,352 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Tests\Icinga\Module\Monitoring\Plugin;
use Icinga\Test\BaseTestCase;
use Icinga\Module\Monitoring\Plugin\Perfdata;
class PerfdataTest extends BaseTestCase
{
/**
* @expectedException Icinga\Exception\ProgrammingError
*/
public function testWhetherFromStringThrowsExceptionWhenGivenAnEmptyString()
{
Perfdata::fromString('');
}
public function testWhetherGetValueReturnsValidValues()
{
$this->assertEquals(
1337.0,
Perfdata::fromString('1337')->getValue(),
'Perfdata::getValue does not return correct values'
);
$this->assertEquals(
1337.0,
Perfdata::fromString('1337;;;;')->getValue(),
'Perfdata::getValue does not return correct values'
);
}
public function testWhetherDecimalValuesAreCorrectlyParsed()
{
$this->assertEquals(
1337.5,
Perfdata::fromString('1337.5')->getValue(),
'Perfdata objects do not parse decimal values correctly'
);
$this->assertEquals(
1337.5,
Perfdata::fromString('1337.5B')->getValue(),
'Perfdata objects do not parse decimal values correctly'
);
}
public function testWhetherGetValueReturnsNullForInvalidOrUnknownValues()
{
$this->assertNull(
Perfdata::fromString('U')->getValue(),
'Perfdata::getValue does not return null for unknown values'
);
$this->assertNull(
Perfdata::fromString('i am not a value')->getValue(),
'Perfdata::getValue does not return null for invalid values'
);
}
public function testWhetherGetWarningTresholdReturnsCorrectValues()
{
$this->assertEquals(
'10',
Perfdata::fromString('1;10')->getWarningTreshold(),
'Perfdata::getWarningTreshold does not return correct values'
);
$this->assertEquals(
'10:',
Perfdata::fromString('1;10:')->getWarningTreshold(),
'Perfdata::getWarningTreshold does not return correct values'
);
$this->assertEquals(
'~:10',
Perfdata::fromString('1;~:10')->getWarningTreshold(),
'Perfdata::getWarningTreshold does not return correct values'
);
$this->assertEquals(
'10:20',
Perfdata::fromString('1;10:20')->getWarningTreshold(),
'Perfdata::getWarningTreshold does not return correct values'
);
$this->assertEquals(
'@10:20',
Perfdata::fromString('1;@10:20')->getWarningTreshold(),
'Perfdata::getWarningTreshold does not return correct values'
);
}
public function testWhetherGetCriticalTresholdReturnsCorrectValues()
{
$this->assertEquals(
'10',
Perfdata::fromString('1;;10')->getCriticalTreshold(),
'Perfdata::getCriticalTreshold does not return correct values'
);
$this->assertEquals(
'10:',
Perfdata::fromString('1;;10:')->getCriticalTreshold(),
'Perfdata::getCriticalTreshold does not return correct values'
);
$this->assertEquals(
'~:10',
Perfdata::fromString('1;;~:10')->getCriticalTreshold(),
'Perfdata::getCriticalTreshold does not return correct values'
);
$this->assertEquals(
'10:20',
Perfdata::fromString('1;;10:20')->getCriticalTreshold(),
'Perfdata::getCriticalTreshold does not return correct values'
);
$this->assertEquals(
'@10:20',
Perfdata::fromString('1;;@10:20')->getCriticalTreshold(),
'Perfdata::getCriticalTreshold does not return correct values'
);
}
public function testWhetherGetMinimumValueReturnsCorrectValues()
{
$this->assertEquals(
1337.0,
Perfdata::fromString('1;;;1337')->getMinimumValue(),
'Perfdata::getMinimumValue does not return correct values'
);
$this->assertEquals(
1337.5,
Perfdata::fromString('1;;;1337.5')->getMinimumValue(),
'Perfdata::getMinimumValue does not return correct values'
);
}
public function testWhetherGetMaximumValueReturnsCorrectValues()
{
$this->assertEquals(
1337.0,
Perfdata::fromString('1;;;;1337')->getMaximumValue(),
'Perfdata::getMaximumValue does not return correct values'
);
$this->assertEquals(
1337.5,
Perfdata::fromString('1;;;;1337.5')->getMaximumValue(),
'Perfdata::getMaximumValue does not return correct values'
);
}
public function testWhetherMissingValuesAreReturnedAsNull()
{
$perfdata = Perfdata::fromString('1;;3;5');
$this->assertNull(
$perfdata->getWarningTreshold(),
'Perfdata objects do not return null for missing 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('666')->isNumber(),
'Perfdata objects do not identify ordinary digits as number'
);
}
/**
* @depends testWhetherGetValueReturnsValidValues
*/
public function testWhetherValuesAreIdentifiedAsSeconds()
{
$this->assertTrue(
Perfdata::fromString('666s')->isSeconds(),
'Perfdata objects do not identify seconds as seconds'
);
$this->assertTrue(
Perfdata::fromString('666us')->isSeconds(),
'Perfdata objects do not identify microseconds as seconds'
);
$this->assertTrue(
Perfdata::fromString('666ms')->isSeconds(),
'Perfdata objects do not identify milliseconds as seconds'
);
}
/**
* @depends testWhetherGetValueReturnsValidValues
*/
public function testWhetherValuesAreIdentifiedAsPercentage()
{
$this->assertTrue(
Perfdata::fromString('66%')->isPercentage(),
'Perfdata objects do not identify percentages as percentages'
);
}
/**
* @depends testWhetherValuesAreIdentifiedAsPercentage
*/
public function testWhetherMinAndMaxAreNotRequiredIfUnitIsInPercent()
{
$perfdata = Perfdata::fromString('1%');
$this->assertEquals(
0.0,
$perfdata->getMinimumValue(),
'Perfdata objects do not set minimum value to 0 if UOM is %'
);
$this->assertEquals(
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('66666B')->isBytes(),
'Perfdata objects do not identify bytes as bytes'
);
$this->assertTrue(
Perfdata::fromString('6666KB')->isBytes(),
'Perfdata objects do not identify kilobytes as bytes'
);
$this->assertTrue(
Perfdata::fromString('666MB')->isBytes(),
'Perfdata objects do not identify megabytes as bytes'
);
$this->assertTrue(
Perfdata::fromString('66GB')->isBytes(),
'Perfdata objects do not identify gigabytes as bytes'
);
$this->assertTrue(
Perfdata::fromString('6TB')->isBytes(),
'Perfdata objects do not identify terabytes as bytes'
);
}
/**
* @depends testWhetherGetValueReturnsValidValues
*/
public function testWhetherValuesAreIdentifiedAsCounter()
{
$this->assertTrue(
Perfdata::fromString('123c')->isCounter(),
'Perfdata objects do not identify counters as counters'
);
}
/**
* @depends testWhetherValuesAreIdentifiedAsSeconds
*/
public function testWhetherMicroSecondsAreCorrectlyConvertedToSeconds()
{
$this->assertEquals(
666 / pow(10, 6),
Perfdata::fromString('666us')->getValue(),
'Perfdata objects do not correctly convert microseconds to seconds'
);
}
/**
* @depends testWhetherValuesAreIdentifiedAsSeconds
*/
public function testWhetherMilliSecondsAreCorrectlyConvertedToSeconds()
{
$this->assertEquals(
666 / pow(10, 3),
Perfdata::fromString('666ms')->getValue(),
'Perfdata objects do not correctly convert microseconds to seconds'
);
}
/**
* @depends testWhetherValuesAreIdentifiedAsPercentage
*/
public function testWhetherPercentagesAreHandledCorrectly()
{
$this->assertEquals(
66.0,
Perfdata::fromString('66%')->getPercentage(),
'Perfdata objects do not correctly handle native percentages'
);
$this->assertEquals(
50.0,
Perfdata::fromString('0;;;-250;250')->getPercentage(),
'Perfdata objects do not correctly convert suitable values to percentages'
);
$this->assertNull(
Perfdata::fromString('50')->getPercentage(),
'Perfdata objects do return a percentage though their unit is not % and no maximum is given'
);
$this->assertNull(
Perfdata::fromString('25;;;50;100')->getPercentage(),
'Perfdata objects do return a percentage though their value is lower than it\'s allowed minimum'
);
}
/**
* @depends testWhetherValuesAreIdentifiedAsBytes
*/
public function testWhetherKiloBytesAreCorrectlyConvertedToBytes()
{
$this->assertEquals(
6666.0 * pow(2, 10),
Perfdata::fromString('6666KB')->getValue(),
'Perfdata objects do not corretly convert kilobytes to bytes'
);
}
/**
* @depends testWhetherValuesAreIdentifiedAsBytes
*/
public function testWhetherMegaBytesAreCorrectlyConvertedToBytes()
{
$this->assertEquals(
666.0 * pow(2, 20),
Perfdata::fromString('666MB')->getValue(),
'Perfdata objects do not corretly convert megabytes to bytes'
);
}
/**
* @depends testWhetherValuesAreIdentifiedAsBytes
*/
public function testWhetherGigaBytesAreCorrectlyConvertedToBytes()
{
$this->assertEquals(
66.0 * pow(2, 30),
Perfdata::fromString('66GB')->getValue(),
'Perfdata objects do not corretly convert gigabytes to bytes'
);
}
/**
* @depends testWhetherValuesAreIdentifiedAsBytes
*/
public function testWhetherTeraBytesAreCorrectlyConvertedToBytes()
{
$this->assertEquals(
6.0 * pow(2, 40),
Perfdata::fromString('6TB')->getValue(),
'Perfdata objects do not corretly convert terabytes to bytes'
);
}
}

View File

@ -508,7 +508,7 @@
// Icinga.debug(req.getResponseHeader('X-Icinga-Redirect'));
} else {
if (errorThrown === 'abort') {
this.icinga.logger.info(
this.icinga.logger.debug(
'Request to ' + url + ' has been aborted for ',
req.$target
);