From f1320b6510b975324afe55c0fa888b4987885439 Mon Sep 17 00:00:00 2001 From: Tony Murray Date: Tue, 19 May 2020 22:08:41 -0500 Subject: [PATCH] Speed up tests by skipping pings (#11642) * Mock fping for module tests, there is no need. Removes some wait time. * fixup some rrd disabling code * oops --- LibreNMS/Fping.php | 91 ++++++++++++++++++++++++++++++ LibreNMS/Util/ModuleTestHelper.php | 9 +-- includes/functions.php | 67 +--------------------- ping.php | 5 +- scripts/collect-port-polling.php | 4 +- tests/FpingTest.php | 9 +-- tests/OSModulesTest.php | 33 +++++++++-- 7 files changed, 134 insertions(+), 84 deletions(-) create mode 100644 LibreNMS/Fping.php diff --git a/LibreNMS/Fping.php b/LibreNMS/Fping.php new file mode 100644 index 0000000000..c6cf1f9a71 --- /dev/null +++ b/LibreNMS/Fping.php @@ -0,0 +1,91 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2020 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS; + +use Log; +use Symfony\Component\Process\Process; + +class Fping +{ + /** + * Run fping against a hostname/ip in count mode and collect stats. + * + * @param string $host + * @param int $count (min 1) + * @param int $interval (min 20) + * @param int $timeout (not more than $interval) + * @param string $address_family ipv4 or ipv6 + * @return array + */ + public function ping($host, $count = 3, $interval = 1000, $timeout = 500, $address_family = 'ipv4') + { + // Default to ipv4 + $fping_name = $address_family == 'ipv6' ? 'fping6' : 'fping'; + $interval = max($interval, 20); + + // build the command + $cmd = [ + Config::get($fping_name, $fping_name), + '-e', + '-q', + '-c', + max($count, 1), + '-p', + $interval, + '-t', + max($timeout, $interval), + $host + ]; + + $process = app()->make(Process::class, ['command' => $cmd]); + Log::debug('[FPING] ' . $process->getCommandLine() . PHP_EOL); + $process->run(); + $output = $process->getErrorOutput(); + + preg_match('#= (\d+)/(\d+)/(\d+)%(, min/avg/max = ([\d.]+)/([\d.]+)/([\d.]+))?$#', $output, $parsed); + [, $xmt, $rcv, $loss, , $min, $avg, $max] = array_pad($parsed, 8, 0); + + if ($loss < 0) { + $xmt = 1; + $rcv = 1; + $loss = 100; + } + + $response = [ + 'xmt' => (int)$xmt, + 'rcv' => (int)$rcv, + 'loss' => (int)$loss, + 'min' => (float)$min, + 'max' => (float)$max, + 'avg' => (float)$avg, + 'dup' => substr_count($output, 'duplicate'), + 'exitcode' => $process->getExitCode(), + ]; + Log::debug('response: ', $response); + + return $response; + } +} diff --git a/LibreNMS/Util/ModuleTestHelper.php b/LibreNMS/Util/ModuleTestHelper.php index 5049807ee6..7c89e66516 100644 --- a/LibreNMS/Util/ModuleTestHelper.php +++ b/LibreNMS/Util/ModuleTestHelper.php @@ -92,11 +92,11 @@ class ModuleTestHelper $this->json_file = $this->json_dir . $this->file_name . ".json"; // never store time series data - Config::set('norrd', true); + Config::set('rrd.enable', false); Config::set('hide_rrd_disabled', true); - Config::set('noinfluxdb', true); - $influxdb = false; - Config::set('nographite', true); + Config::set('influxdb.enable', false); + Config::set('graphite.enable', false); + Config::set('prometheus.enable', false); if (is_null(self::$module_tables)) { // only load the yaml once, then keep it in memory @@ -505,6 +505,7 @@ class ModuleTestHelper public function generateTestData(Snmpsim $snmpsim, $no_save = false) { global $device, $debug, $vdebug; + Config::set('rrd.enable', false); // disable rrd if (!is_file($this->snmprec_file)) { throw new FileNotFoundException("$this->snmprec_file does not exist!"); diff --git a/includes/functions.php b/includes/functions.php index 37aa470ca7..eaf433aff7 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -21,6 +21,7 @@ use LibreNMS\Exceptions\HostUnreachablePingException; use LibreNMS\Exceptions\InvalidPortAssocModeException; use LibreNMS\Exceptions\LockException; use LibreNMS\Exceptions\SnmpVersionUnsupportedException; +use LibreNMS\Fping; use LibreNMS\Util\IPv4; use LibreNMS\Util\IPv6; use LibreNMS\Util\MemcacheLock; @@ -676,7 +677,7 @@ function isPingable($hostname, $address_family = 'ipv4', $attribs = []) ]; } - $status = fping( + $status = app()->make(Fping::class)->ping( $hostname, Config::get('fping_options.count', 3), Config::get('fping_options.interval', 500), @@ -1459,70 +1460,6 @@ function device_has_ip($ip) return false; // not an ipv4 or ipv6 address... } -/** - * Run fping against a hostname/ip in count mode and collect stats. - * - * @param string $host - * @param int $count (min 1) - * @param int $interval (min 20) - * @param int $timeout (not more than $interval) - * @param string $address_family ipv4 or ipv6 - * @return array - */ -function fping($host, $count = 3, $interval = 1000, $timeout = 500, $address_family = 'ipv4') -{ - // Default to ipv4 - $fping_name = $address_family == 'ipv6' ? 'fping6' : 'fping'; - $interval = max($interval, 20); - - // build the command - $cmd = [ - Config::get($fping_name, $fping_name), - '-e', - '-q', - '-c', - max($count, 1), - '-p', - $interval, - '-t', - max($timeout, $interval), - $host - ]; - - $process = app()->make(Process::class, ['command' => $cmd]); - d_echo('[FPING] ' . $process->getCommandLine() . PHP_EOL); - $process->run(); - $output = $process->getErrorOutput(); - - preg_match('#= (\d+)/(\d+)/(\d+)%(, min/avg/max = ([\d.]+)/([\d.]+)/([\d.]+))?$#', $output, $parsed); - [, $xmt, $rcv, $loss, , $min, $avg, $max] = array_pad($parsed, 8, 0); - - if ($loss < 0) { - $xmt = 1; - $rcv = 1; - $loss = 100; - } - - $response = [ - 'xmt' => (int)$xmt, - 'rcv' => (int)$rcv, - 'loss' => (int)$loss, - 'min' => (float)$min, - 'max' => (float)$max, - 'avg' => (float)$avg, - 'dup' => substr_count($output, 'duplicate'), - 'exitcode' => $process->getExitCode(), - ]; - d_echo($response); - - return $response; -} - -function function_check($function) -{ - return function_exists($function); -} - /** * Try to determine the address family (IPv4 or IPv6) associated with an SNMP * transport specifier (like "udp", "udp6", etc.). diff --git a/ping.php b/ping.php index c49000b2e2..6d8b1b87c5 100755 --- a/ping.php +++ b/ping.php @@ -2,6 +2,7 @@ 0, ]; - $actual = fping('192.168.1.3'); + $actual = app()->make(Fping::class)->ping('192.168.1.3'); $this->assertSame($expected, $actual); } @@ -66,7 +67,7 @@ class FpingTest extends TestCase "exitcode" => 0, ]; - $actual = fping('192.168.1.7'); + $actual = app()->make(Fping::class)->ping('192.168.1.7'); $this->assertSame($expected, $actual); } @@ -87,7 +88,7 @@ class FpingTest extends TestCase "exitcode" => 1, ]; - $actual = fping('192.168.53.1'); + $actual = app()->make(Fping::class)->ping('192.168.53.1'); $this->assertSame($expected, $actual); } @@ -113,7 +114,7 @@ OUT; "exitcode" => 1, ]; - $actual = fping('192.168.1.2'); + $actual = app()->make(Fping::class)->ping('192.168.1.2'); $this->assertSame($expected, $actual); } diff --git a/tests/OSModulesTest.php b/tests/OSModulesTest.php index eb8268383b..a3742488a9 100644 --- a/tests/OSModulesTest.php +++ b/tests/OSModulesTest.php @@ -29,6 +29,7 @@ use DeviceCache; use LibreNMS\Config; use LibreNMS\Exceptions\FileNotFoundException; use LibreNMS\Exceptions\InvalidModuleException; +use LibreNMS\Fping; use LibreNMS\Util\ModuleTestHelper; class OSModulesTest extends DBTestCase @@ -82,12 +83,8 @@ class OSModulesTest extends DBTestCase public function testOS($os, $variant, $modules) { $this->requireSnmpsim(); // require snmpsim for tests - - // stub out Log::event, we don't need to store them for these tests - $this->app->bind('log', function ($app) { - return \Mockery::mock('\App\Facades\LogManager[event]', [$app]) - ->shouldReceive('event'); - }); + // stub out Log::event and Fping->ping, we don't need to store them for these tests + $this->stubClasses(); try { set_debug(false); // avoid all undefined index errors in the legacy code @@ -158,4 +155,28 @@ class OSModulesTest extends DBTestCase return [[false, false, $e->getMessage()]]; } } + + private function stubClasses(): void + { + $this->app->bind('log', function ($app) { + return \Mockery::mock('\App\Facades\LogManager[event]', [$app]) + ->shouldReceive('event'); + }); + + $this->app->bind(Fping::class, function ($app) { + $mock = \Mockery::mock('\LibreNMS\Fping'); + $mock->shouldReceive('ping')->andReturn([ + "xmt" => 3, + "rcv" => 3, + "loss" => 0, + "min" => 0.62, + "max" => 0.93, + "avg" => 0.71, + "dup" => 0, + "exitcode" => 0, + ]); + + return $mock; + }); + } }