diff --git a/LibreNMS/Data/Graphing/GraphImage.php b/LibreNMS/Data/Graphing/GraphImage.php index 26ab7cb84f..0263b1fb3d 100644 --- a/LibreNMS/Data/Graphing/GraphImage.php +++ b/LibreNMS/Data/Graphing/GraphImage.php @@ -25,36 +25,12 @@ namespace LibreNMS\Data\Graphing; +use LibreNMS\Enum\ImageFormat; + class GraphImage { - /** - * @var string - */ - private $type; - /** - * @var string - */ - private $title; - /** - * @var string - */ - private $data; - - public function __construct(string $type, string $title, string $data) + public function __construct(public readonly ImageFormat $format, public readonly string $title, public readonly string $data) { - $this->type = $type; - $this->title = $title; - $this->data = $data; - } - - public function title(): string - { - return $this->title; - } - - public function data(): string - { - return $this->data; } public function base64(): string @@ -64,28 +40,21 @@ class GraphImage public function inline(): string { - return 'data:' . $this->imageType() . ';base64,' . $this->base64(); + return 'data:' . $this->contentType() . ';base64,' . $this->base64(); } public function fileExtension(): string { - switch ($this->imageType()) { - case 'image/svg+xml': - return 'svg'; - case 'image/png': - // fallthrough - default: - return 'png'; - } + return $this->format->name; } - public function imageType(): string + public function contentType(): string { - return $this->type; + return $this->format->contentType(); } public function __toString() { - return $this->data(); + return $this->data; } } diff --git a/LibreNMS/Data/Graphing/GraphParameters.php b/LibreNMS/Data/Graphing/GraphParameters.php new file mode 100644 index 0000000000..b5adaca79b --- /dev/null +++ b/LibreNMS/Data/Graphing/GraphParameters.php @@ -0,0 +1,242 @@ +. + * + * @link https://www.librenms.org + * + * @copyright 2022 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Data\Graphing; + +use App\Facades\DeviceCache; +use Illuminate\Support\Str; +use LibreNMS\Config; +use LibreNMS\Enum\ImageFormat; +use LibreNMS\Util\Clean; +use LibreNMS\Util\Time; + +class GraphParameters +{ + public readonly array $visibleElements; + + public string $title; + public readonly string $type; + public readonly string $subtype; + public readonly ImageFormat $imageFormat; + + public readonly string $font; + public readonly string $font_color; + public readonly int $font_size; + public readonly string $background; + public readonly string $canvas; + + public readonly int $width; + public readonly int $height; + public readonly bool $full_size; + public readonly bool $is_small; + + public readonly int $from; + public readonly int $to; + public readonly int $period; + public readonly int $prev_from; + + public readonly bool $inverse; + public readonly string $in; + public readonly string $out; + public ?int $scale_max = null; + public ?int $scale_min = null; + public ?bool $scale_rigid = null; + public bool $sloped = true; + + public int $float_precision = 2; + + private const TINY = 99; + private const SMALL = 224; + private const MEDIUM_SMALL = 300; + private const MEDIUM = 350; + + public function __construct(array $vars) + { + $this->imageFormat = ImageFormat::forGraph($vars['graph_type'] ?? null); + [$this->type, $this->subtype] = $this->extractType($vars['type'] ?? ''); + + $this->width = (int) ($vars['width'] ?? 400); + $this->height = (int) ($vars['height'] ?? $this->width / 3); + $this->full_size = ! empty($vars['absolute']); + $this->is_small = $this->width < self::SMALL; + + $this->font = Config::get('mono_font'); + $this->font_color = Clean::alphaDash($vars['font']); + $this->font_size = $this->width <= self::MEDIUM_SMALL ? 8 : 7; + + $this->canvas = Clean::alphaDash($vars['bg'] ?? ''); + $this->background = Clean::alphaDash($vars['bbg'] ?? ''); + + $this->title = $vars['graph_title'] ?? $this->defaultTitle(); + $this->visibleElements = [ + 'title' => empty($vars['title']) || $vars['title'] !== 'no', + 'legend' => empty($vars['legend']) || $vars['legend'] !== 'no', + 'total' => ! ($vars['nototal'] ?? $this->is_small), + 'details' => ! ($vars['nodetails'] ?? $this->is_small), + 'aggregate' => ! empty($vars['noagg']), + ]; + + $this->from = Time::parseAt($vars['from'] ?? '-1d'); + $this->to = empty($vars['to']) ? time() : Time::parseAt($vars['to']); + $this->period = $this->to - $this->from; + $this->prev_from = $this->from - $this->period; + + $this->inverse = ! empty($vars['inverse']); + $this->in = $this->inverse ? 'out' : 'in'; + $this->out = $this->inverse ? 'in' : 'out'; + } + + public function visible(string $element): bool + { + return $this->visibleElements[$element] ?? true; + } + + public function all(): array + { + $variables = get_object_vars($this); + + // legacy compat + $variables['nototal'] = ! $this->visibleElements['total']; + $variables['nodetails'] = ! $this->visibleElements['details']; + $variables['noagg'] = ! $this->visibleElements['aggregate']; + $variables['title'] = $this->visibleElements['title']; + + return $variables; + } + + public function toRrdOptions(): array + { + $options = ['--start', $this->from, '--end', $this->to, '--width', $this->width, '--height', $this->height]; + + // image must fit final dimensions + if ($this->full_size) { + $options[] = '--full-size-mode'; + } + + if ($this->imageFormat === ImageFormat::svg) { + $options[] = '--imgformat=SVG'; + if ($this->width < self::MEDIUM) { + array_push($options, '-m', 0.75, '-R', 'light'); + } + } + + // set up fonts + array_push($options, '--font', 'LEGEND:' . $this->font_size . ':' . $this->font); + array_push($options, '--font', 'AXIS:' . ($this->font_size - 1) . ':' . $this->font); + array_push($options, '--font-render-mode', 'normal'); + + // set up colors + foreach ($this->graphColors() as $name => $color) { + array_push($options, '-c', $name . '#' . $color); + } + + // set up scaling scaling + if (! $this->scale_min && ! $this->scale_max) { + $options[] = '--alt-autoscale-max'; + if ($this->scale_rigid === null) { + $this->scale_rigid = true; + } + } + if ($this->scale_min) { + array_push($options, '-l', $this->scale_min); + } + if ($this->scale_max) { + array_push($options, '-u', $this->scale_max); + } + if ($this->scale_rigid) { + $options[] = '--rigid'; + } + + if ($this->sloped) { + $options[] = '--slope-mode'; + } + + // remove all text, height is too small + if ($this->height < self::TINY) { + $options[] = '--only-graph'; + } + + if (! $this->visible('legend')) { + $options[] = '-g'; + } + + if ($this->visible('title') && $this->title) { + $options[] = "--title='" . Clean::alphaDashSpace($this->title) . "'"; + } + + return $options; + } + + public function __toString(): string + { + return implode(' ', $this->toRrdOptions()); + } + + private function graphColors(): array + { + $config_suffix = Config::get('applied_site_style') == 'dark' ? '_dark' : ''; + $def_colors = Config::get('rrdgraph_def_text' . $config_suffix); + $def_font = ltrim(Config::get('rrdgraph_def_text_color' . $config_suffix), '#'); + + preg_match_all('/-c ([A-Z]+)#([0-9A-Fa-f]{6,8})/', $def_colors, $matches); + $colors = ['FONT' => $def_font]; + foreach ($matches[1] as $index => $key) { + $colors[$key] = $matches[2][$index]; + } + + // user overrides + if ($this->font_color) { + $colors['FONT'] = $this->font_color; + } + + if ($this->canvas) { + $colors['CANVAS'] = $this->canvas; + } + + if ($this->background) { + $colors['BACK'] = $this->background; + } + + return $colors; + } + + private function extractType(string $type): array + { + preg_match('/^(?P[A-Za-z0-9]+)_(?P.+)/', $type, $graphtype); + $type = basename($graphtype['type']); + $subtype = basename($graphtype['subtype']); + + return [$type, $subtype]; + } + + private function defaultTitle(): string + { + $title = DeviceCache::getPrimary()->displayName() ?: ucfirst($this->type); + $title .= ' - '; + $title .= Str::title(str_replace('_', ' ', $this->subtype)); + + return $title; + } +} diff --git a/LibreNMS/Enum/ImageFormat.php b/LibreNMS/Enum/ImageFormat.php new file mode 100644 index 0000000000..7e949e6f1b --- /dev/null +++ b/LibreNMS/Enum/ImageFormat.php @@ -0,0 +1,44 @@ +. + * + * @link https://www.librenms.org + * + * @copyright 2022 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Enum; + +use LibreNMS\Config; + +enum ImageFormat : string +{ + case png = 'png'; + case svg = 'svg'; + + public static function forGraph(?string $type = null): ImageFormat + { + return ImageFormat::tryFrom($type ?? Config::get('webui.graph_type')) ?? ImageFormat::png; + } + + public function contentType(): string + { + return $this->value == 'svg' ? 'image/svg+xml' : 'image/png'; + } +} diff --git a/LibreNMS/Util/Graph.php b/LibreNMS/Util/Graph.php index 0ed05f84e4..2eb11a7957 100644 --- a/LibreNMS/Util/Graph.php +++ b/LibreNMS/Util/Graph.php @@ -27,9 +27,12 @@ namespace LibreNMS\Util; use App\Facades\DeviceCache; use App\Models\Device; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; use LibreNMS\Config; use LibreNMS\Data\Graphing\GraphImage; +use LibreNMS\Data\Graphing\GraphParameters; +use LibreNMS\Enum\ImageFormat; use LibreNMS\Exceptions\RrdGraphException; use Rrd; @@ -65,7 +68,7 @@ class Graph return self::getImage($vars)->base64(); } - return self::getImage($vars)->data(); + return self::getImage($vars)->data; } /** @@ -84,7 +87,7 @@ class Graph throw $e; } - return new GraphImage(self::imageType(), 'Error', $e->generateErrorImage()); + return new GraphImage(ImageFormat::forGraph(), 'Error', $e->generateErrorImage()); } } @@ -111,28 +114,31 @@ class Graph $vars = Url::parseLegacyPathVars($vars); } - [$type, $subtype] = extract_graph_type($vars['type']); - - $graph_title = ''; if (isset($vars['device'])) { $device = device_by_id_cache(is_numeric($vars['device']) ? $vars['device'] : getidbyname($vars['device'])); DeviceCache::setPrimary($device['device_id']); - - //set default graph title - $graph_title = DeviceCache::getPrimary()->displayName(); } // variables for included graphs - $width = $vars['width'] ?? 400; - $height = $vars['height'] ?? $width / 3; - $title = $vars['title'] ?? ''; - $vertical = $vars['vertical'] ?? ''; - $legend = $vars['legend'] ?? false; - $from = parse_at_time($vars['from'] ?? '-1d'); - $to = empty($vars['to']) ? time() : parse_at_time($vars['to']); - $period = ($to - $from); - $prev_from = ($from - $period); - $graph_image_type = $vars['graph_type'] ?? Config::get('webui.graph_type'); + $graph_params = new GraphParameters($vars); + // set php variables for legacy graphs + $type = $graph_params->type; + $subtype = $graph_params->subtype; + $height = $graph_params->height; + $width = $graph_params->width; + $from = $graph_params->from; + $to = $graph_params->to; + $period = $graph_params->period; + $prev_from = $graph_params->prev_from; + $inverse = $graph_params->inverse; + $in = $graph_params->in; + $out = $graph_params->out; + $float_precision = $graph_params->float_precision; + $title = $graph_params->visible('title'); + $nototal = ! $graph_params->visible('total'); + $nodetails = ! $graph_params->visible('details'); + $noagg = ! $graph_params->visible('aggregate'); + $rrd_options = ''; $rrd_filename = null; @@ -152,22 +158,17 @@ class Graph throw new RrdGraphException("{$type}_$subtype template missing", "{$type}_$subtype missing", $width, $height); } - if ($graph_image_type === 'svg') { - $rrd_options .= ' --imgformat=SVG'; - if ($width < 350) { - $rrd_options .= ' -m 0.75 -R light'; - } - } - if (empty($rrd_options)) { throw new RrdGraphException('Graph Definition Error', 'Def Error', $width, $height); } + $rrd_options = $graph_params . ' ' . $rrd_options; + // Generating the graph! try { $image_data = Rrd::graph($rrd_options); - return new GraphImage(self::imageType($graph_image_type), $title ?? $graph_title, $image_data); + return new GraphImage($graph_params->imageFormat, $graph_params->title, $image_data); } catch (RrdGraphException $e) { // preserve original error if debug is enabled, otherwise make it a little more user friendly if (Debug::isEnabled()) { @@ -236,34 +237,19 @@ class Graph return Config::get("graph_types.$type.$subtype.section") == 'mib'; } - public static function getOverviewGraphsForDevice($device) + public static function getOverviewGraphsForDevice(Device $device): array { if ($device->snmp_disable) { - return Config::getOsSetting('ping', 'over'); + return Arr::wrap(Config::getOsSetting('ping', 'over')); } if ($graphs = Config::getOsSetting($device->os, 'over')) { - return $graphs; + return Arr::wrap($graphs); } $os_group = Config::getOsSetting($device->os, 'group'); - return Config::get("os_group.$os_group.over", Config::get('os.default.over')); - } - - /** - * Get the http content type of the image - * - * @param string|null $type svg or png - * @return string - */ - public static function imageType(?string $type = null): string - { - if ($type === null) { - $type = Config::get('webui.graph_type'); - } - - return $type === 'svg' ? 'image/svg+xml' : 'image/png'; + return Arr::wrap(Config::get("os_group.$os_group.over", Config::get('os.default.over'))); } /** diff --git a/LibreNMS/Util/Mail.php b/LibreNMS/Util/Mail.php index 6cd74c46cc..a6f3ad5a43 100644 --- a/LibreNMS/Util/Mail.php +++ b/LibreNMS/Util/Mail.php @@ -148,13 +148,13 @@ class Mail $image = Graph::getImage($url); // attach image - $fileName = substr(Clean::fileName($image->title() ?: $cid), 0, 250); + $fileName = substr(Clean::fileName($image->title ?: $cid), 0, 250); $mail->addStringEmbeddedImage( - $image->data(), + $image->data, $cid, $fileName . '.' . $image->fileExtension(), PHPMailer::ENCODING_BASE64, - $image->imageType() + $image->format->contentType() ); // update image tag to link to attached image, or just the image name diff --git a/LibreNMS/Util/Time.php b/LibreNMS/Util/Time.php index 9e8ad6e4fb..9bda555b19 100644 --- a/LibreNMS/Util/Time.php +++ b/LibreNMS/Util/Time.php @@ -132,4 +132,35 @@ class Time return implode(' ,', $ret); } + + /** + * Parse a time string into a timestamp including signed relative times using: + * m - month + * d - day + * h - hour + * y - year + */ + public static function parseAt(string|int $time): int + { + if (is_numeric($time)) { + return $time < 0 ? time() + $time : intval($time); + } + + if (preg_match('/^[+-]\d+[hdmy]$/', $time)) { + $units = [ + 'm' => 60, + 'h' => 3600, + 'd' => 86400, + 'y' => 31557600, + ]; + $value = Number::cast(substr($time, 1, -1)); + $unit = substr($time, -1); + + $offset = ($time[0] == '-' ? -1 : 1) * $units[$unit] * $value; + + return time() + $offset; + } + + return (int) strtotime($time); + } } diff --git a/app/Http/Controllers/GraphController.php b/app/Http/Controllers/GraphController.php index 9ead73a55b..c422eef8cc 100644 --- a/app/Http/Controllers/GraphController.php +++ b/app/Http/Controllers/GraphController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Http\Response; use LibreNMS\Config; +use LibreNMS\Enum\ImageFormat; use LibreNMS\Exceptions\RrdGraphException; use LibreNMS\Util\Debug; use LibreNMS\Util\Graph; @@ -33,20 +34,20 @@ class GraphController extends Controller } $headers = [ - 'Content-type' => $graph->imageType(), + 'Content-type' => $graph->contentType(), ]; if ($output == 'base64') { return response($graph, 200, $headers); } - return response($graph->data(), 200, $headers); + return response($graph->data, 200, $headers); } catch (RrdGraphException $e) { if (Debug::isEnabled()) { throw $e; } - return response($e->generateErrorImage(), 500, ['Content-type' => Graph::imageType()]); + return response($e->generateErrorImage(), 500, ['Content-type' => ImageFormat::forGraph()->contentType()]); } } } diff --git a/doc/Developing/os/Custom-Graphs.md b/doc/Developing/os/Custom-Graphs.md index 402cf01280..e417469eed 100644 --- a/doc/Developing/os/Custom-Graphs.md +++ b/doc/Developing/os/Custom-Graphs.md @@ -74,7 +74,7 @@ includes/html/graphs/device/pulse_sessions.inc.php $rrd_filename = Rrd::name($device['hostname'], 'pulse_sessions'); -require 'includes/graphs/common.inc.php'; +require 'includes/html/graphs/common.inc.php'; $ds = 'sessions'; diff --git a/includes/html/api_functions.inc.php b/includes/html/api_functions.inc.php index c04e5c7ccf..5ce1b1287a 100644 --- a/includes/html/api_functions.inc.php +++ b/includes/html/api_functions.inc.php @@ -91,10 +91,10 @@ function api_get_graph(array $vars) $graph = Graph::get($vars); if ($vars['output'] === 'base64') { - return api_success(['image' => $graph->base64(), 'content-type' => $graph->imageType()], 'image'); + return api_success(['image' => $graph->base64(), 'content-type' => $graph->contentType()], 'image'); } - return response($graph->data(), 200, ['Content-Type' => $graph->imageType()]); + return response($graph->data, 200, ['Content-Type' => $graph->contentType()]); } catch (\LibreNMS\Exceptions\RrdGraphException $e) { return api_error(500, $e->getMessage()); } diff --git a/includes/html/functions.inc.php b/includes/html/functions.inc.php index 99f9b1b24f..55f4079996 100644 --- a/includes/html/functions.inc.php +++ b/includes/html/functions.inc.php @@ -989,17 +989,6 @@ function eventlog_severity($eventlog_severity) } } // end eventlog_severity -/** - * Get the http content type of the image - * - * @param string $type svg or png - * @return string - */ -function get_image_type(string $type) -{ - return \LibreNMS\Util\Graph::imageType($type); -} - function get_oxidized_nodes_list() { $context = stream_context_create([ @@ -1045,36 +1034,6 @@ function generate_stacked_graphs($transparency = '88') } } -/** - * Parse AT time spec, does not handle the entire spec. - * - * @param string|int $time - * @return int - */ -function parse_at_time($time) -{ - if (is_numeric($time)) { - return $time < 0 ? time() + $time : intval($time); - } - - if (preg_match('/^[+-]\d+[hdmy]$/', $time)) { - $units = [ - 'm' => 60, - 'h' => 3600, - 'd' => 86400, - 'y' => 31557600, - ]; - $value = substr($time, 1, -1); - $unit = substr($time, -1); - - $offset = ($time[0] == '-' ? -1 : 1) * $units[$unit] * $value; - - return time() + $offset; - } - - return (int) strtotime($time); -} - /** * Returns the sysname of a device with a html line break prepended. * if the device has an empty sysname it will return device's hostname instead diff --git a/includes/html/graphs/common.inc.php b/includes/html/graphs/common.inc.php index c6af9a5ae9..309315ce50 100644 --- a/includes/html/graphs/common.inc.php +++ b/includes/html/graphs/common.inc.php @@ -1,119 +1,7 @@ scale_max = isset($scale_max) ? (int) $scale_max : $graph_params->scale_max; +$graph_params->scale_min = isset($scale_min) ? (int) $scale_min : $graph_params->scale_min; +$graph_params->scale_rigid = $scale_rigid ?? $graph_params->scale_rigid; +$graph_params->title = $graph_title ?? $graph_params->title; diff --git a/includes/html/graphs/graph.inc.php b/includes/html/graphs/graph.inc.php index 2de8b81602..c016a350cf 100644 --- a/includes/html/graphs/graph.inc.php +++ b/includes/html/graphs/graph.inc.php @@ -1,37 +1,41 @@ type; +$subtype = $graph_params->subtype; +$height = $graph_params->height; +$width = $graph_params->width; +$from = $graph_params->from; +$to = $graph_params->to; +$period = $graph_params->period; +$prev_from = $graph_params->prev_from; +$inverse = $graph_params->inverse; +$in = $graph_params->in; +$out = $graph_params->out; +$float_precision = $graph_params->float_precision; +$title = $graph_params->visible('title'); +$nototal = ! $graph_params->visible('total'); +$nodetails = ! $graph_params->visible('details'); +$noagg = ! $graph_params->visible('aggregate'); $rrd_options = ''; require Config::get('install_dir') . "/includes/html/graphs/$type/auth.inc.php"; -//set default graph title -$graph_title = format_hostname($device); - if ($auth && is_customoid_graph($type, $subtype)) { $unit = $vars['unit']; include Config::get('install_dir') . '/includes/html/graphs/customoid/customoid.inc.php'; @@ -49,12 +53,7 @@ if ($auth === null) { return; } -if ($graph_image_type === 'svg') { - $rrd_options .= ' --imgformat=SVG'; - if ($width < 350) { - $rrd_options .= ' -m 0.75 -R light'; - } -} +$rrd_options = $graph_params . ' ' . $rrd_options; // command output requested if (! empty($command_only)) { @@ -88,9 +87,9 @@ try { // output the graph if (\LibreNMS\Util\Debug::isEnabled()) { - echo 'graph'; + echo 'graph'; } else { - header('Content-type: ' . get_image_type(Config::get('webui.graph_type'))); + header('Content-type: ' . ImageFormat::forGraph()->contentType()); echo $output === 'base64' ? base64_encode($image_data) : $image_data; } } catch (\LibreNMS\Exceptions\RrdGraphException $e) { diff --git a/includes/html/pages/graphs.inc.php b/includes/html/pages/graphs.inc.php index abd190133e..1b7fe65ce5 100644 --- a/includes/html/pages/graphs.inc.php +++ b/includes/html/pages/graphs.inc.php @@ -1,6 +1,7 @@ [A-Za-z0-9]+)_(?P.+)/', $vars['type'], $graphtype); @@ -188,6 +189,7 @@ if (! $auth) { } if (! empty($vars['showcommand'])) { + $vars = $graph_array; $_GET = $graph_array; $command_only = 1; diff --git a/misc/config_definitions.json b/misc/config_definitions.json index 76e5e48b6c..9af6845b15 100644 --- a/misc/config_definitions.json +++ b/misc/config_definitions.json @@ -4935,11 +4935,11 @@ "type": "text" }, "rrdgraph_def_text": { - "default": "-c BACK#EEEEEE00 -c SHADEA#EEEEEE00 -c SHADEB#EEEEEE00 -c CANVAS#FFFFFF00 -c GRID#a5a5a5 -c MGRID#FF9999 -c FRAME#5e5e5e -c ARROW#5e5e5e -R normal", + "default": "-c BACK#EEEEEE00 -c SHADEA#EEEEEE00 -c SHADEB#EEEEEE00 -c CANVAS#FFFFFF00 -c GRID#a5a5a5 -c MGRID#FF9999 -c FRAME#5e5e5e -c ARROW#5e5e5e", "type": "text" }, "rrdgraph_def_text_dark": { - "default": "-c BACK#EEEEEE00 -c SHADEA#EEEEEE00 -c SHADEB#EEEEEE00 -c CANVAS#FFFFFF00 -c GRID#292929 -c MGRID#2f343e -c FRAME#5e5e5e -c ARROW#5e5e5e -R normal", + "default": "-c BACK#EEEEEE00 -c SHADEA#EEEEEE00 -c SHADEB#EEEEEE00 -c CANVAS#FFFFFF00 -c GRID#292929 -c MGRID#2f343e -c FRAME#5e5e5e -c ARROW#5e5e5e", "type": "text" }, "rrdgraph_def_text_color": { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 8d71e20979..034ecdd74b 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -5411,22 +5411,12 @@ parameters: path: LibreNMS/Util/GitHub.php - - message: "#^Method LibreNMS\\\\Util\\\\Graph\\:\\:getOverviewGraphsForDevice\\(\\) has no return type specified\\.$#" + message: "#^Unreachable statement \\- code above always terminates\\.$#" count: 1 path: LibreNMS/Util/Graph.php - - message: "#^Method LibreNMS\\\\Util\\\\Graph\\:\\:getOverviewGraphsForDevice\\(\\) has parameter \\$device with no type specified\\.$#" - count: 1 - path: LibreNMS/Util/Graph.php - - - - message: "#^Result of && is always false\\.$#" - count: 1 - path: LibreNMS/Util/Graph.php - - - - message: "#^Variable \\$rrd_filename in isset\\(\\) always exists and is always null\\.$#" + message: "#^Variable \\$rrd_options in empty\\(\\) always exists and is always falsy\\.$#" count: 1 path: LibreNMS/Util/Graph.php diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php index 7f70935919..7d1d14ce3e 100644 --- a/tests/FunctionsTest.php +++ b/tests/FunctionsTest.php @@ -27,6 +27,7 @@ namespace LibreNMS\Tests; use LibreNMS\Device\YamlDiscovery; use LibreNMS\Util\Rewrite; +use LibreNMS\Util\Time; class FunctionsTest extends TestCase { @@ -102,20 +103,20 @@ class FunctionsTest extends TestCase public function testParseAtTime() { - $this->assertEquals(time(), parse_at_time('now'), 'now did not match'); - $this->assertEquals(time() + 180, parse_at_time('+3m'), '+3m did not match'); - $this->assertEquals(time() + 7200, parse_at_time('+2h'), '+2h did not match'); - $this->assertEquals(time() + 172800, parse_at_time('+2d'), '+2d did not match'); - $this->assertEquals(time() + 63115200, parse_at_time('+2y'), '+2y did not match'); - $this->assertEquals(time() - 180, parse_at_time('-3m'), '-3m did not match'); - $this->assertEquals(time() - 7200, parse_at_time('-2h'), '-2h did not match'); - $this->assertEquals(time() - 172800, parse_at_time('-2d'), '-2d did not match'); - $this->assertEquals(time() - 63115200, parse_at_time('-2y'), '-2y did not match'); - $this->assertEquals(429929439, parse_at_time('429929439')); - $this->assertEquals(212334234, parse_at_time(212334234)); - $this->assertEquals(time() - 43, parse_at_time('-43'), '-43 did not match'); - $this->assertEquals(0, parse_at_time('invalid')); - $this->assertEquals(606614400, parse_at_time('March 23 1989 UTC')); - $this->assertEquals(time() + 86400, parse_at_time('+1 day')); + $this->assertEquals(time(), Time::parseAt('now'), 'now did not match'); + $this->assertEquals(time() + 180, Time::parseAt('+3m'), '+3m did not match'); + $this->assertEquals(time() + 7200, Time::parseAt('+2h'), '+2h did not match'); + $this->assertEquals(time() + 172800, Time::parseAt('+2d'), '+2d did not match'); + $this->assertEquals(time() + 63115200, Time::parseAt('+2y'), '+2y did not match'); + $this->assertEquals(time() - 180, Time::parseAt('-3m'), '-3m did not match'); + $this->assertEquals(time() - 7200, Time::parseAt('-2h'), '-2h did not match'); + $this->assertEquals(time() - 172800, Time::parseAt('-2d'), '-2d did not match'); + $this->assertEquals(time() - 63115200, Time::parseAt('-2y'), '-2y did not match'); + $this->assertEquals(429929439, Time::parseAt('429929439')); + $this->assertEquals(212334234, Time::parseAt(212334234)); + $this->assertEquals(time() - 43, Time::parseAt('-43'), '-43 did not match'); + $this->assertEquals(0, Time::parseAt('invalid')); + $this->assertEquals(606614400, Time::parseAt('March 23 1989 UTC')); + $this->assertEquals(time() + 86400, Time::parseAt('+1 day')); } }