mirror of
https://github.com/librenms/librenms.git
synced 2024-09-21 02:18:39 +00:00
Rewrite development helper to lnms dev:check (#11650)
* Refactor pre-commit to class * docs build * dusk check * ci mode for checks * full checks * other mysql * make other lint checks actually work fix pylint finding * ci is a long opt * fix undefined index * dusk fully working * ask for forgiveness, not permission * fix whitespace * skip dusk sometimes * Handle 3com and other os with digits * flags instead of if else spaghetti * convert to command * cleanup * missed check * fixes * case * self-check :D * argument now * fix bugs from refactors * another fix * adjust file change parsing * refactor execut a bit * fallback to global quiet when unknown type. * allow quiet override for specific commands * output cleanup * check flow * start of tests * file categorizer tests and fixes * fixes and cleanup * skipable not implemented... * more tests, fix bugs * more tests and cleanup * wrong command * fix canCheck and set env properly * full env fix * don't allow dusk on user's run as it will erase their db. * fix os option * fix whitespace * don't need to start server * ci doesn't like that
This commit is contained in:
parent
0b7373d973
commit
ce21011aff
25
.travis.yml
25
.travis.yml
@ -11,11 +11,11 @@ matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- php: 7.4
|
||||
env: SKIP_STYLE_CHECK=1
|
||||
env: SKIP_STYLE_CHECK=1 SKIP_WEB_CHECK=1
|
||||
- php: 7.3
|
||||
env: SKIP_UNIT_CHECK=1 BROWSER_TEST=1 CHROME_HEADLESS=1
|
||||
env: SKIP_UNIT_CHECK=1
|
||||
- php: 7.2
|
||||
env: SKIP_STYLE_CHECK=1 EXECUTE_BUILD_DOCS=true
|
||||
env: SKIP_STYLE_CHECK=1 SKIP_WEB_CHECK=1 EXECUTE_BUILD_DOCS=true
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@ -31,26 +31,15 @@ before_install:
|
||||
|
||||
install:
|
||||
- travis_retry composer install --no-interaction --prefer-dist --no-suggest
|
||||
- pip3 install --user snmpsim
|
||||
- pip install --user mysql-python pylint
|
||||
- pip3 install --user snmpsim PyMySQL pylint
|
||||
- test -n "$SKIP_WEB_CHECK" || php artisan dusk:update --detect
|
||||
|
||||
after_failure:
|
||||
- tail /tmp/snmpsimd.log
|
||||
|
||||
before_script:
|
||||
- phpenv config-rm xdebug.ini
|
||||
- test -z "$BROWSER_TEST" || php artisan dusk:update --detect
|
||||
- test -z "$BROWSER_TEST" || php artisan serve --env=dusk.testing 2>/dev/null &
|
||||
- test -n "$SKIP_WEB_CHECK" || php artisan serve --env=dusk.testing 2>/dev/null &
|
||||
|
||||
script:
|
||||
- set -e
|
||||
- export FILES=$(git diff --diff-filter=d --name-only master | tr '\n' ' '|sed 's/,*$//g')
|
||||
- php scripts/pre-commit.php -q -l
|
||||
- php scripts/pre-commit.php -q -s
|
||||
- php scripts/pre-commit.php -u --db --snmpsim --fail-fast
|
||||
- test -z "$BROWSER_TEST" || php artisan config:clear
|
||||
- test -z "$BROWSER_TEST" || php artisan dusk
|
||||
- bash -n daily.sh
|
||||
- pylint -E poller-wrapper.py discovery-wrapper.py services-wrapper.py
|
||||
- bash scripts/deploy-docs.sh
|
||||
- set +e
|
||||
- php artisan dev:check ci
|
||||
|
71
LibreNMS/Util/Categorizer.php
Normal file
71
LibreNMS/Util/Categorizer.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* Categorizer.php
|
||||
*
|
||||
* Categorize a list of items according to a dynamic list
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2020 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Util;
|
||||
|
||||
class Categorizer
|
||||
{
|
||||
protected $items;
|
||||
protected $categorized = [];
|
||||
protected $categories = [];
|
||||
protected $skippable;
|
||||
|
||||
public function __construct($items = [])
|
||||
{
|
||||
$this->skippable = function ($item) {
|
||||
return false;
|
||||
};
|
||||
$this->items = $items;
|
||||
}
|
||||
|
||||
public function addCategory(string $category, callable $function)
|
||||
{
|
||||
$this->categories[$category] = $function;
|
||||
$this->categorized[$category] = [];
|
||||
}
|
||||
|
||||
public function setSkippable(callable $function)
|
||||
{
|
||||
$this->skippable = $function;
|
||||
}
|
||||
|
||||
public function categorize()
|
||||
{
|
||||
foreach ($this->items as $item) {
|
||||
foreach ($this->categories as $category => $test) {
|
||||
if (call_user_func($this->skippable, $item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = call_user_func($test, $item);
|
||||
if ($result !== false) {
|
||||
$this->categorized[$category][] = $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->categorized;
|
||||
}
|
||||
}
|
521
LibreNMS/Util/CiHelper.php
Normal file
521
LibreNMS/Util/CiHelper.php
Normal file
@ -0,0 +1,521 @@
|
||||
<?php
|
||||
/**
|
||||
* CiHelper.php
|
||||
*
|
||||
* Code for CI operation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2020 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Util;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class CiHelper
|
||||
{
|
||||
private $changedFiles;
|
||||
private $changed;
|
||||
private $os;
|
||||
private $unitEnv = [];
|
||||
private $duskEnv = ['APP_ENV' => 'testing'];
|
||||
|
||||
private $completedChecks = [
|
||||
'lint' => false,
|
||||
'style' => false,
|
||||
'unit' => false,
|
||||
'web' => false,
|
||||
];
|
||||
private $ciDefaults = [
|
||||
'quiet' => [
|
||||
'lint' => true,
|
||||
'style' => true,
|
||||
'unit' => false,
|
||||
'web' => false,
|
||||
],
|
||||
];
|
||||
private $flags = [
|
||||
'lint_enable' => true,
|
||||
'style_enable' => true,
|
||||
'unit_enable' => true,
|
||||
'web_enable' => false,
|
||||
'lint_skip' => false,
|
||||
'style_skip' => false,
|
||||
'unit_skip' => false,
|
||||
'web_skip' => false,
|
||||
'lint_skip_php' => false,
|
||||
'lint_skip_python' => false,
|
||||
'lint_skip_bash' => false,
|
||||
'unit_os' => false,
|
||||
'unit_docs' => false,
|
||||
'unit_svg' => false,
|
||||
'unit_modules' => false,
|
||||
'docs_changed' => false,
|
||||
'ci' => false,
|
||||
'commands' => false,
|
||||
'fail-fast' => false,
|
||||
'full' => false,
|
||||
'quiet' => false,
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function enable($check, $enabled = true)
|
||||
{
|
||||
$this->flags["{$check}_enable"] = $enabled;
|
||||
}
|
||||
|
||||
public function duskHeadless()
|
||||
{
|
||||
$this->duskEnv['CHROME_HEADLESS'] = 1;
|
||||
}
|
||||
|
||||
public function enableDb()
|
||||
{
|
||||
$this->unitEnv['DBTEST'] = 1;
|
||||
}
|
||||
|
||||
public function enableSnmpsim()
|
||||
{
|
||||
$this->unitEnv['SNMPSIM'] = 1;
|
||||
}
|
||||
|
||||
public function setModules(array $modules)
|
||||
{
|
||||
$this->unitEnv['TEST_MODULES'] = implode(',', $modules);
|
||||
$this->flags['unit_modules'] = true;
|
||||
$this->enableDb();
|
||||
$this->enableSnmpsim();
|
||||
}
|
||||
|
||||
public function setOS(array $os)
|
||||
{
|
||||
$this->os = $os;
|
||||
$this->flags['unit_os'] = true;
|
||||
$this->enableDb();
|
||||
$this->enableSnmpsim();
|
||||
}
|
||||
|
||||
public function setFlags(array $flags)
|
||||
{
|
||||
foreach (array_intersect_key($flags, $this->flags) as $key => $value) {
|
||||
$this->flags[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$return = 0;
|
||||
foreach (array_keys($this->completedChecks) as $check) {
|
||||
$ret = $this->runCheck($check);
|
||||
|
||||
if ($this->flags['fail-fast'] && $ret !== 0 && $ret !== 250) {
|
||||
return $return;
|
||||
} else {
|
||||
$return += $ret;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that all possible checks have been completed
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function allChecksComplete()
|
||||
{
|
||||
return array_reduce($this->completedChecks, function ($result, $check) {
|
||||
return $result && $check;
|
||||
}, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flag value
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function getFlag($name)
|
||||
{
|
||||
return $this->flags[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all flags
|
||||
* @return bool[]
|
||||
*/
|
||||
public function getFlags()
|
||||
{
|
||||
return $this->flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs phpunit
|
||||
*
|
||||
* @return int the return value from phpunit (0 = success)
|
||||
*/
|
||||
public function checkUnit()
|
||||
{
|
||||
$phpunit_bin = $this->checkPhpExec('phpunit');
|
||||
|
||||
$phpunit_cmd = "$phpunit_bin --colors=always";
|
||||
|
||||
if ($this->flags['fail-fast']) {
|
||||
$phpunit_cmd .= ' --stop-on-error --stop-on-failure';
|
||||
}
|
||||
|
||||
// exclusive tests
|
||||
if ($this->flags['unit_os']) {
|
||||
$selected_os = $this->os ?: $this->changed['os'];
|
||||
echo 'Only checking os: ' . implode(', ', $selected_os) . PHP_EOL;
|
||||
$filter = implode('.*|', $selected_os);
|
||||
// include tests that don't have data providers and only data sets that match
|
||||
$phpunit_cmd .= " --group os --filter '/::test[A-Za-z]+$|::test[A-Za-z]+ with data set \"$filter.*\"$/'";
|
||||
} elseif ($this->flags['unit_docs']) {
|
||||
$phpunit_cmd .= " --group docs";
|
||||
} elseif ($this->flags['unit_svg']) {
|
||||
$phpunit_cmd .= ' tests/SVGTest.php';
|
||||
} elseif ($this->flags['unit_modules']) {
|
||||
$phpunit_cmd .= ' tests/OSModulesTest.php';
|
||||
}
|
||||
|
||||
return $this->execute('unit', $phpunit_cmd, false, $this->unitEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs phpcs --standard=PSR2 against the code base
|
||||
*
|
||||
* @return int the return value from phpcs (0 = success)
|
||||
*/
|
||||
public function checkStyle()
|
||||
{
|
||||
$phpcs_bin = $this->checkPhpExec('phpcs');
|
||||
|
||||
$files = ($this->flags['full']) ? './' : implode(' ', $this->changed['php']);
|
||||
|
||||
$cs_cmd = "$phpcs_bin -n -p --colors --extensions=php --standard=misc/phpcs_librenms.xml $files";
|
||||
|
||||
return $this->execute('style', $cs_cmd);
|
||||
}
|
||||
|
||||
public function checkWeb()
|
||||
{
|
||||
if (!$this->getFlag('ci')) {
|
||||
echo "Warning: dusk may erase your primary database, do not use yet\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($this->canCheck('web')) {
|
||||
echo "Preparing for web checks\n";
|
||||
$this->execute('config:clear', ['php', 'artisan', 'config:clear'], true);
|
||||
$this->execute('dusk:update', ['php', 'artisan', 'dusk:update', '--detect'], true);
|
||||
|
||||
// check if web server is running
|
||||
$server = new Process(['php', '-S', '127.0.0.1:8000', base_path('server.php')], public_path(), ['APP_ENV' => 'dusk.testing']);
|
||||
$server->setTimeout(3600)
|
||||
->setIdleTimeout(3600)
|
||||
->start();
|
||||
$server->waitUntil(function ($type, $output) {
|
||||
return strpos($output, 'Development Server (http://127.0.0.1:8000) started') !== false;
|
||||
});
|
||||
if ($server->isRunning()) {
|
||||
echo "Started server http://127.0.0.1:8000\n";
|
||||
}
|
||||
}
|
||||
|
||||
$dusk_cmd = "php artisan dusk";
|
||||
|
||||
if ($this->flags['fail-fast']) {
|
||||
$dusk_cmd .= ' --stop-on-error --stop-on-failure';
|
||||
}
|
||||
|
||||
return $this->execute('web', $dusk_cmd, false, $this->duskEnv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs php -l and tests for any syntax errors
|
||||
*
|
||||
* @return int the return value from running php -l (0 = success)
|
||||
*/
|
||||
public function checkLint()
|
||||
{
|
||||
$return = 0;
|
||||
if (!$this->flags['lint_skip_php']) {
|
||||
$parallel_lint_bin = $this->checkPhpExec('parallel-lint');
|
||||
|
||||
// matches a substring of the relative path, leading / is treated as absolute path
|
||||
$lint_excludes = ['vendor/'];
|
||||
$lint_exclude = $this->buildPhpLintExcludes('--exclude ', $lint_excludes);
|
||||
|
||||
$files = $this->flags['full'] ? './' : implode(' ', $this->changed['php']);
|
||||
|
||||
$php_lint_cmd = "$parallel_lint_bin $lint_exclude $files";
|
||||
|
||||
$return += $this->execute('PHP lint', $php_lint_cmd);
|
||||
}
|
||||
|
||||
if (!$this->flags['lint_skip_python']) {
|
||||
$pylint_bin = $this->checkPythonExec('pylint');
|
||||
|
||||
$files = $this->flags['full']
|
||||
? str_replace(PHP_EOL, ' ', rtrim(shell_exec("find . -name '*.py' -not -path './vendor/*' -not -path './tests/*'")))
|
||||
: implode(' ', $this->changed['python']);
|
||||
|
||||
$py_lint_cmd = "$pylint_bin -E -j 0 $files";
|
||||
$return += $this->execute('Python lint', $py_lint_cmd);
|
||||
}
|
||||
|
||||
if (!$this->flags['lint_skip_bash']) {
|
||||
$files = $this->flags['full']
|
||||
? explode(PHP_EOL, rtrim(shell_exec("find . -name '*.sh' -not -path './node_modules/*' -not -path './vendor/*'")))
|
||||
: $this->changed['bash'];
|
||||
|
||||
$bash_cmd = implode(' && ', array_map(function ($file) {
|
||||
return "bash -n $file";
|
||||
}, $files));
|
||||
$return += $this->execute('Bash lint', $bash_cmd);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the specified check and return the return value.
|
||||
* Make sure it isn't skipped by SKIP_TYPE_CHECK env variable and hasn't been run already
|
||||
*
|
||||
* @param string $type type of check lint, style, or unit
|
||||
* @return int the return value from the check (0 = success)
|
||||
*/
|
||||
private function runCheck($type)
|
||||
{
|
||||
if ($method = $this->canCheck($type)) {
|
||||
$ret = $this->$method();
|
||||
$this->completedChecks[$type] = true;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($this->flags["{$type}_skip"]) {
|
||||
echo ucfirst($type) . " check skipped.\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @return false|string the method name to run
|
||||
*/
|
||||
private function canCheck($type)
|
||||
{
|
||||
if ($this->flags["{$type}_skip"] || $this->completedChecks[$type]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$method = 'check' . ucfirst($type);
|
||||
if (method_exists($this, $method) && $this->flags["{$type}_enable"]) {
|
||||
return $method;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a check command
|
||||
*
|
||||
* @param string $name name for status output
|
||||
* @param string|array $command
|
||||
* @param bool $silence silence the status ouput (still shows error output)
|
||||
* @param array $env environment to set
|
||||
* @return int
|
||||
*/
|
||||
private function execute(string $name, $command, $silence = false, $env = null): int
|
||||
{
|
||||
$start = microtime(true);
|
||||
$proc = new Process($command, null, $env);
|
||||
|
||||
if ($this->flags['commands']) {
|
||||
$prefix = '';
|
||||
if ($env) {
|
||||
$prefix .= http_build_query($env, '', ' ') . ' ';
|
||||
}
|
||||
|
||||
echo $prefix . $proc->getCommandLine() . PHP_EOL;
|
||||
return 250;
|
||||
}
|
||||
|
||||
if (!$silence) {
|
||||
echo "Running $name check... ";
|
||||
}
|
||||
|
||||
$space = strrpos($name, ' ');
|
||||
$type = substr($name, $space ? $space + 1 : 0);
|
||||
$quiet = ($this->flags['ci'] && isset($this->ciDefaults['quiet'][$type])) ? $this->ciDefaults['quiet'][$type] : $this->flags['quiet'];
|
||||
|
||||
$proc->setTimeout(3600)->setIdleTimeout(3600);
|
||||
if (!($silence || $quiet)) {
|
||||
echo PHP_EOL;
|
||||
$proc->setTty(Process::isTtySupported());
|
||||
}
|
||||
|
||||
$proc->run();
|
||||
|
||||
$duration = sprintf('%.2fs', microtime(true) - $start);
|
||||
if ($proc->getExitCode() > 0) {
|
||||
if (!$silence) {
|
||||
echo "failed ($duration)\n";
|
||||
}
|
||||
if ($quiet || $silence) {
|
||||
echo $proc->getOutput() . PHP_EOL;
|
||||
echo $proc->getErrorOutput() . PHP_EOL;
|
||||
}
|
||||
} elseif (!$silence) {
|
||||
echo "success ($duration)\n";
|
||||
}
|
||||
|
||||
return $proc->getExitCode();
|
||||
}
|
||||
|
||||
|
||||
public function checkEnvSkips()
|
||||
{
|
||||
$this->flags['unit_skip'] = (bool)getenv('SKIP_UNIT_CHECK');
|
||||
$this->flags['lint_skip'] = (bool)getenv('SKIP_LINT_CHECK');
|
||||
$this->flags['web_skip'] = (bool)getenv('SKIP_WEB_CHECK');
|
||||
$this->flags['style_skip'] = (bool)getenv('SKIP_STYLE_CHECK');
|
||||
}
|
||||
|
||||
public function detectChangedFiles()
|
||||
{
|
||||
$files = trim(getenv('FILES'));
|
||||
$changed_files = $files ?: shell_exec("git diff --diff-filter=d --name-only master | tr '\n' ' '|sed 's/,*$//g'");
|
||||
$this->changedFiles = $changed_files ? explode(' ', $changed_files) : [];
|
||||
|
||||
$this->changed = (new FileCategorizer($this->changedFiles))->categorize();
|
||||
|
||||
$this->parseChangedFiles();
|
||||
}
|
||||
|
||||
private function parseChangedFiles()
|
||||
{
|
||||
if (empty($this->changedFiles) || $this->flags['full']) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setFlags([
|
||||
'lint_skip_php' => empty($this->changed['php']),
|
||||
'lint_skip_python' => empty($this->changed['python']),
|
||||
'lint_skip_bash' => empty($this->changed['bash']),
|
||||
'unit_os' => $this->getFlag('unit_os') || (!empty($this->changed['os']) && empty(array_diff($this->changed['php'], $this->changed['os-files']))),
|
||||
'unit_docs' => !empty($this->changed['docs']) && empty($this->changed['php']),
|
||||
'unit_svg' => !empty($this->changed['svg']) && empty($this->changed['php']),
|
||||
'docs_changed' => !empty($this->changed['docs']),
|
||||
'full' => !empty($this->changed['full-checks']),
|
||||
]);
|
||||
|
||||
$this->setFlags([
|
||||
'unit_skip' => empty($this->changed['php']) && !array_sum(Arr::only($this->getFlags(), ['unit_os', 'unit_docs', 'unit_svg', 'unit_modules', 'docs_changed'])),
|
||||
'lint_skip' => array_sum(Arr::only($this->getFlags(), ['lint_skip_php', 'lint_skip_python', 'lint_skip_bash'])) === 3,
|
||||
'style_skip' => empty($this->changed['php']),
|
||||
'web_skip' => empty($this->changed['php']) && empty($this->changed['resources']),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a PHP executable and return the path to it
|
||||
* If it does not exist, run composer.
|
||||
* If composer isn't installed, print error and exit.
|
||||
*
|
||||
* @param string $exec the name of the executable to check
|
||||
* @return string path to the executable
|
||||
*/
|
||||
private function checkPhpExec($exec)
|
||||
{
|
||||
$path = "vendor/bin/$exec";
|
||||
|
||||
if (is_executable($path)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
echo "Running composer install to install developer dependencies.\n";
|
||||
passthru("scripts/composer_wrapper.php install");
|
||||
|
||||
if (is_executable($path)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
echo "\nRunning installing deps with composer failed.\n You should try running './scripts/composer_wrapper.php install' by hand\n";
|
||||
echo "You can find more info at http://docs.librenms.org/Developing/Validating-Code/\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a Python executable and return the path to it
|
||||
* If it does not exist, run pip3.
|
||||
* If pip3 isn't installed, print error and exit.
|
||||
*
|
||||
* @param string $exec the name of the executable to check
|
||||
* @return string path to the executable
|
||||
*/
|
||||
private function checkPythonExec($exec)
|
||||
{
|
||||
$home = getenv('HOME');
|
||||
$path = "$home/.local/bin/$exec";
|
||||
|
||||
if (is_executable($path)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
// check system
|
||||
$system_path = rtrim(exec("which pylint 2>/dev/null"));
|
||||
if (is_executable($system_path)) {
|
||||
return $system_path;
|
||||
}
|
||||
|
||||
echo "Running pip3 install to install developer dependencies.\n";
|
||||
passthru("pip3 install $exec"); // probably wrong in other cases...
|
||||
|
||||
if (is_executable($path)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
echo "\nRunning installing deps with pip3 failed.\n You should try running 'pip3 install -r requirements.txt' by hand\n";
|
||||
echo "You can find more info at http://docs.librenms.org/Developing/Validating-Code/\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list of exclude arguments from an array
|
||||
*
|
||||
* @param string $exclude_string such as "--exclude"
|
||||
* @param array $excludes array of directories to exclude
|
||||
* @return string resulting string
|
||||
*/
|
||||
private function buildPhpLintExcludes($exclude_string, $excludes)
|
||||
{
|
||||
$result = '';
|
||||
foreach ($excludes as $exclude) {
|
||||
$result .= $exclude_string . $exclude . ' ';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
137
LibreNMS/Util/FileCategorizer.php
Normal file
137
LibreNMS/Util/FileCategorizer.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* FileCategorizer.php
|
||||
*
|
||||
* Categorizes files in LibreNMS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2020 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Util;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class FileCategorizer extends Categorizer
|
||||
{
|
||||
private const TESTS_REGEX = '#^tests/(snmpsim|data)/(([0-9a-z\-]+)(_[0-9a-z\-]+)?)(_[0-9a-z\-]+)?\.(json|snmprec)$#';
|
||||
|
||||
public function __construct($items = [])
|
||||
{
|
||||
parent::__construct($items);
|
||||
|
||||
if (getenv('CIHELPER_DEBUG')) {
|
||||
$this->setSkippable(function ($item) {
|
||||
return in_array($item, ['.travis.yml', 'LibreNMS/Util/CiHelper.php', 'LibreNMS/Util/FileCategorizer.php']);
|
||||
});
|
||||
}
|
||||
|
||||
$this->addCategory('php', function ($item) {
|
||||
return Str::endsWith($item, '.php') ? $item : false;
|
||||
});
|
||||
$this->addCategory('docs', function ($item) {
|
||||
return (Str::startsWith($item, 'doc/') || $item == 'mkdocs.yml') ? $item : false;
|
||||
});
|
||||
$this->addCategory('python', function ($item) {
|
||||
return Str::endsWith($item, '.py') ? $item : false;
|
||||
});
|
||||
$this->addCategory('bash', function ($item) {
|
||||
return Str::endsWith($item, '.sh') ? $item : false;
|
||||
});
|
||||
$this->addCategory('svg', function ($item) {
|
||||
return Str::endsWith($item, '.svg') ? $item : false;
|
||||
});
|
||||
$this->addCategory('resources', function ($item) {
|
||||
return Str::startsWith($item, 'resources/') ? $item : false;
|
||||
});
|
||||
$this->addCategory('full-checks', function ($item) {
|
||||
return in_array($item, ['composer.lock', '.travis.yml']) ? $item : false;
|
||||
});
|
||||
$this->addCategory('os-files', function ($item) {
|
||||
if (($os_name = $this->osFromFile($item)) !== null) {
|
||||
return ['os' => $os_name, 'file' => $item];
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public function categorize()
|
||||
{
|
||||
parent::categorize();
|
||||
|
||||
// split out os
|
||||
$this->categorized['os'] = array_unique(array_column($this->categorized['os-files'], 'os'));
|
||||
$this->categorized['os-files'] = array_column($this->categorized['os-files'], 'file');
|
||||
|
||||
// If we have more than 4 (arbitrary number) of OS' then blank them out
|
||||
// Unit tests may take longer to run in a loop so fall back to all.
|
||||
if (count($this->categorized['os']) > 4) {
|
||||
$this->categorized['full-checks'] = [true];
|
||||
}
|
||||
|
||||
return $this->categorized;
|
||||
}
|
||||
|
||||
private function validateOs($os)
|
||||
{
|
||||
return file_exists("includes/definitions/$os.yaml") ? $os : null;
|
||||
}
|
||||
|
||||
private function osFromFile($file)
|
||||
{
|
||||
if (Str::startsWith($file, 'includes/definitions/')) {
|
||||
return basename($file, '.yaml');
|
||||
} elseif (Str::startsWith($file, ['includes/polling', 'includes/discovery'])) {
|
||||
return $this->validateOs(basename($file, '.inc.php'));
|
||||
} elseif (preg_match('#LibreNMS/OS/[^/]+.php#', $file)) {
|
||||
return $this->osFromClass(basename($file, '.php'));
|
||||
} elseif (preg_match(self::TESTS_REGEX, $file, $matches)) {
|
||||
if ($this->validateOs($matches[3])) {
|
||||
return $matches[3];
|
||||
}
|
||||
if ($this->validateOs($matches[2])) {
|
||||
return $matches[2];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert class name to os name
|
||||
*
|
||||
* @param string $class
|
||||
* @return string|null
|
||||
*/
|
||||
private function osFromClass($class)
|
||||
{
|
||||
preg_match_all("/[A-Z][a-z0-9]*/", $class, $segments);
|
||||
$osname = implode('-', array_map('strtolower', $segments[0]));
|
||||
$osname = preg_replace(
|
||||
['/^zero-/', '/^one-/', '/^two-/', '/^three-/', '/^four-/', '/^five-/', '/^six-/', '/^seven-/', '/^eight-/', '/^nine-/',],
|
||||
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
|
||||
$osname
|
||||
);
|
||||
|
||||
if ($os = $this->validateOs($osname)) {
|
||||
return $os;
|
||||
}
|
||||
return $this->validateOs(str_replace('-', '_', $osname));
|
||||
}
|
||||
}
|
@ -35,8 +35,8 @@ def call_script(script, args=()):
|
||||
base_dir = os.path.realpath(os.path.dirname(__file__) + "/..")
|
||||
cmd = base + ("{}/{}".format(base_dir, script),) + tuple(map(str, args))
|
||||
debug("Running {}".format(cmd))
|
||||
# preexec_fn=os.setsid here keeps process signals from propagating
|
||||
return subprocess.check_output(cmd, stderr=subprocess.STDOUT, preexec_fn=os.setsid, close_fds=True).decode()
|
||||
# preexec_fn=os.setsid here keeps process signals from propagating (close_fds=True is default)
|
||||
return subprocess.check_output(cmd, stderr=subprocess.STDOUT, preexec_fn=os.setsid).decode()
|
||||
|
||||
|
||||
class DB:
|
||||
|
122
app/Console/Commands/DevCheckCommand.php
Normal file
122
app/Console/Commands/DevCheckCommand.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* DevCheckCommand.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2020 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Console\LnmsCommand;
|
||||
use Illuminate\Support\Arr;
|
||||
use LibreNMS\Util\CiHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class DevCheckCommand extends LnmsCommand
|
||||
{
|
||||
protected $developer = true;
|
||||
protected $name = 'dev:check';
|
||||
|
||||
/** @var CiHelper */
|
||||
protected $helper;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->addArgument('check', InputArgument::OPTIONAL, __('commands.dev:check.arguments.check', ['checks' => '[unit, lint, style, dusk]']), 'all');
|
||||
$this->addOption('os', 'o', InputOption::VALUE_REQUIRED);
|
||||
$this->addOption('module', 'm', InputOption::VALUE_REQUIRED);
|
||||
$this->addOption('fail-fast', 'f', InputOption::VALUE_NONE);
|
||||
$this->addOption('quiet', 'q', InputOption::VALUE_NONE);
|
||||
$this->addOption('db', null, InputOption::VALUE_NONE);
|
||||
$this->addOption('snmpsim', null, InputOption::VALUE_NONE);
|
||||
$this->addOption('full', null, InputOption::VALUE_NONE);
|
||||
$this->addOption('commands', 'c', InputOption::VALUE_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->helper = new CiHelper();
|
||||
$this->parseInput();
|
||||
$this->helper->detectChangedFiles();
|
||||
$this->helper->checkEnvSkips();
|
||||
|
||||
$result = $this->helper->run();
|
||||
|
||||
if (getenv('EXECUTE_BUILD_DOCS') && $this->helper->getFlag('docs_changed')) {
|
||||
exec('bash scripts/deploy-docs.sh');
|
||||
}
|
||||
|
||||
if ($result == 0 && $this->helper->allChecksComplete()) {
|
||||
$this->line("\033[32mTests ok, submit away :)\033[0m");
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function parseInput()
|
||||
{
|
||||
$check = $this->argument('check');
|
||||
if (!in_array($check, ['all', 'lint', 'style', 'unit', 'web', 'ci'])) {
|
||||
$this->error("Invalid check: $check");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$this->helper->setFlags(Arr::only($this->options(), ['quiet', 'commands', 'fail-fast', 'full']));
|
||||
|
||||
$all = $check == 'all' || $check == 'ci';
|
||||
$this->helper->enable('style', $all || $check === 'style');
|
||||
$this->helper->enable('lint', $all || $check === 'lint');
|
||||
$this->helper->enable('unit', $all || $check === 'unit');
|
||||
$this->helper->enable('web', $all || $check === 'web');
|
||||
|
||||
if ($os = $this->option('os')) {
|
||||
$this->helper->setFlags(['style_enable' => false, 'lint_enable' => false, 'unit_enable' => true, 'web_enable' => false]);
|
||||
$this->helper->setOS(explode(',', $os));
|
||||
}
|
||||
|
||||
if ($modules = $this->option('module')) {
|
||||
$this->helper->setFlags(['style_enable' => false, 'lint_enable' => false, 'unit_enable' => true, 'web_enable' => false]);
|
||||
$this->helper->setModules(explode(',', $modules));
|
||||
}
|
||||
|
||||
if ($check == 'ci') {
|
||||
$this->helper->setFlags(['ci' => true]);
|
||||
$this->helper->duskHeadless();
|
||||
$this->helper->enableSnmpsim();
|
||||
$this->helper->enableDb();
|
||||
}
|
||||
|
||||
if ($this->option('snmpsim')) {
|
||||
$this->helper->enableSnmpsim();
|
||||
}
|
||||
|
||||
if ($this->option('db')) {
|
||||
$this->helper->enableDb();
|
||||
}
|
||||
}
|
||||
}
|
@ -47,7 +47,8 @@ abstract class LnmsCommand extends Command
|
||||
|
||||
public function isHidden()
|
||||
{
|
||||
return $this->hidden || ($this->developer && $this->getLaravel()->environment() !== 'production');
|
||||
$env = $this->getLaravel() ? $this->getLaravel()->environment() : getenv('APP_ENV');
|
||||
return $this->hidden || ($this->developer && $env !== 'production');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,6 +27,22 @@ return [
|
||||
'no-validation' => 'Cannot set :setting, it is missing validation definition.',
|
||||
]
|
||||
],
|
||||
'dev:check' => [
|
||||
'description' => 'LibreNMS code checks. Running with no options runs all checks',
|
||||
'arguments' => [
|
||||
'check' => 'Run the specified check :checks',
|
||||
],
|
||||
'options' => [
|
||||
'commands' => 'Print commands that would be run only, no checks',
|
||||
'db' => 'Run unit tests that require a database connection',
|
||||
'fail-fast' => 'Stop checks when any failure is encountered',
|
||||
'full' => 'Run full checks ignoring changed file filtering',
|
||||
'module' => 'Specific Module to run tests on. Implies unit, --db, --snmpsim',
|
||||
'os' => 'Specific OS to run tests on. Implies unit, --db, --snmpsim',
|
||||
'quiet' => 'Hide output unless there is an error',
|
||||
'snmpsim' => 'Use snmpsim for unit tests',
|
||||
]
|
||||
],
|
||||
'user:add' => [
|
||||
'description' => 'Add a local user, you can only log in with this user if auth is set to mysql',
|
||||
'arguments' => [
|
||||
|
@ -1,456 +1,5 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
$filename = basename(__FILE__);
|
||||
$install_dir = realpath(__DIR__ . '/..');
|
||||
chdir($install_dir);
|
||||
|
||||
require $install_dir . '/vendor/autoload.php';
|
||||
|
||||
if (getenv('FILES')) {
|
||||
$changed_files = rtrim(getenv('FILES'));
|
||||
} else {
|
||||
$changed_files = exec("git diff --diff-filter=d --name-only master | tr '\n' ' '|sed 's/,*$//g'");
|
||||
}
|
||||
|
||||
$changed_files = $changed_files ? explode(' ', $changed_files) : [];
|
||||
|
||||
$map = [
|
||||
'docs' => 0,
|
||||
'python' => 0,
|
||||
'bash' => 0,
|
||||
'php' => 0,
|
||||
'os-php' => 0,
|
||||
'os' => [],
|
||||
];
|
||||
|
||||
foreach ($changed_files as $file) {
|
||||
if (Str::startsWith($file, 'doc/')) {
|
||||
$map['docs']++;
|
||||
}
|
||||
if (Str::endsWith($file, '.py')) {
|
||||
$map['python']++;
|
||||
}
|
||||
if (Str::endsWith($file, '.sh')) {
|
||||
$map['bash']++;
|
||||
}
|
||||
|
||||
// cause full tests to run
|
||||
if ($file == 'composer.lock' || $file == '.travis.yml') {
|
||||
$map['php']++;
|
||||
}
|
||||
|
||||
// check if os owned file or generic php file
|
||||
if (!empty($os_name = os_from_file($file))) {
|
||||
$map['os'][] = $os_name;
|
||||
if (Str::endsWith($file, '.php')) {
|
||||
$map['os-php']++;
|
||||
}
|
||||
} elseif (Str::endsWith($file, '.php')) {
|
||||
$map['php']++;
|
||||
}
|
||||
}
|
||||
|
||||
$map['os'] = array_unique($map['os']);
|
||||
|
||||
$short_opts = 'lsufqcho:m:';
|
||||
$long_opts = array(
|
||||
'lint',
|
||||
'style',
|
||||
'unit',
|
||||
'os:',
|
||||
'module:',
|
||||
'fail-fast',
|
||||
'quiet',
|
||||
'snmpsim',
|
||||
'db',
|
||||
'commands',
|
||||
'help',
|
||||
);
|
||||
$options = getopt($short_opts, $long_opts);
|
||||
|
||||
if (check_opt($options, 'h', 'help')) {
|
||||
echo "LibreNMS Code Tests Script
|
||||
Running $filename without options runs all checks.
|
||||
-l, --lint Run php lint checks to test for valid syntax
|
||||
-s, --style Run phpcs check to check for PSR-2 compliance
|
||||
-u, --unit Run phpunit tests
|
||||
-o, --os Specific OS to run tests on. Implies --unit, --db, --snmpsim
|
||||
-m, --module Specific Module to run tests on. Implies --unit, --db, --snmpsim
|
||||
-f, --fail-fast Quit when any failure is encountered
|
||||
-q, --quiet Hide output unless there is an error
|
||||
--db Run unit tests that require a database
|
||||
--snmpsim Use snmpsim for unit tests
|
||||
-c, --commands Print commands only, no checks
|
||||
-h, --help Show this help text.\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
// set up some variables
|
||||
$passthru = !check_opt($options, 'q', 'quiet');
|
||||
$command_only = check_opt($options, 'c', 'commands');
|
||||
$fail_fast = check_opt($options, 'f', 'fail-fast');
|
||||
$return = 0;
|
||||
$completed_tests = array(
|
||||
'lint' => false,
|
||||
'style' => false,
|
||||
'unit' => false,
|
||||
);
|
||||
$docs_only = false;
|
||||
|
||||
if ($os = check_opt($options, 'os', 'o')) {
|
||||
// enable unit tests, snmpsim, and db
|
||||
$options['u'] = false;
|
||||
$options['snmpsim'] = false;
|
||||
$options['db'] = false;
|
||||
}
|
||||
|
||||
if ($module = check_opt($options, 'm', 'module')) {
|
||||
putenv("TEST_MODULES=$module");
|
||||
// enable unit tests, snmpsim, and db
|
||||
$options['u'] = false;
|
||||
$options['snmpsim'] = false;
|
||||
$options['db'] = false;
|
||||
}
|
||||
|
||||
$all = !check_opt($options, 'l', 'lint', 's', 'style', 'u', 'unit');
|
||||
if ($all) {
|
||||
// no test specified, run all tests in this order
|
||||
$options += array('u' => false, 's' => false, 'l' => false);
|
||||
}
|
||||
|
||||
if (check_opt($options, 'snmpsim')) {
|
||||
putenv('SNMPSIM=1');
|
||||
}
|
||||
|
||||
if (check_opt($options, 'db')) {
|
||||
putenv('DBTEST=1');
|
||||
}
|
||||
|
||||
// No php files, skip the php checks.
|
||||
if (!empty($changed_files) && $map['php'] === 0 && $map['os-php'] === 0) {
|
||||
putenv('SKIP_LINT_CHECK=1');
|
||||
putenv('SKIP_STYLE_CHECK=1');
|
||||
}
|
||||
|
||||
// If we have no php files and no OS' found then also skip unit checks.
|
||||
if (!empty($changed_files) && $map['php'] === 0 && empty($map['os']) && !$os) {
|
||||
if ($map['docs'] > 0) {
|
||||
$docs_only = true;
|
||||
} else {
|
||||
putenv('SKIP_UNIT_CHECK=1');
|
||||
}
|
||||
}
|
||||
|
||||
// If we have more than 4 (arbitrary number) of OS' then blank them out
|
||||
// Unit tests may take longer to run in a loop so fall back to all.
|
||||
if (count($map['os']) > 4) {
|
||||
unset($map['os']);
|
||||
}
|
||||
|
||||
// run tests in the order they were specified
|
||||
|
||||
foreach (array_keys($options) as $opt) {
|
||||
$ret = 0;
|
||||
if ($opt == 'l' || $opt == 'lint') {
|
||||
$ret = run_check('lint', $passthru, $command_only);
|
||||
} elseif ($opt == 's' || $opt == 'style') {
|
||||
$ret = run_check('style', $passthru, $command_only);
|
||||
} elseif ($opt == 'u' || $opt == 'unit') {
|
||||
if (!empty($map['os']) && $map['php'] === 0) {
|
||||
$os = $map['os'];
|
||||
}
|
||||
|
||||
if (!empty($os)) {
|
||||
echo 'Only checking os: ' . implode(', ', (array)$os) . PHP_EOL;
|
||||
}
|
||||
|
||||
$ret = run_check('unit', $passthru, $command_only, compact('fail_fast', 'os', 'module', 'docs_only'));
|
||||
}
|
||||
|
||||
if ($fail_fast && $ret !== 0 && $ret !== 250) {
|
||||
exit($ret);
|
||||
} else {
|
||||
$return += $ret;
|
||||
}
|
||||
}
|
||||
|
||||
// output Tests ok, if no arguments passed
|
||||
if ($all && $return === 0) {
|
||||
echo "\033[32mTests ok, submit away :)\033[0m \n";
|
||||
}
|
||||
exit($return); //return the combined/single return value of tests
|
||||
|
||||
function os_from_file($file)
|
||||
{
|
||||
if (Str::startsWith($file, 'includes/definitions/')) {
|
||||
return basename($file, '.yaml');
|
||||
} elseif (Str::startsWith($file, ['includes/polling', 'includes/discovery'])) {
|
||||
return os_from_php($file);
|
||||
} elseif (Str::startsWith($file, 'LibreNMS/OS/')) {
|
||||
if (preg_match('#LibreNMS/OS/[^/]+.php#', $file)) {
|
||||
// convert class name to os name
|
||||
preg_match_all("/[A-Z][a-z]*/", basename($file, '.php'), $segments);
|
||||
$osname = implode('-', array_map('strtolower', $segments[0]));
|
||||
$os = os_from_php($osname);
|
||||
if ($os) {
|
||||
return $os;
|
||||
}
|
||||
return os_from_php(str_replace('-', '_', $osname));
|
||||
}
|
||||
} elseif (Str::startsWith($file, ['tests/snmpsim/', 'tests/data/'])) {
|
||||
list($os,) = explode('_', basename(basename($file, '.json'), '.snmprec'), 2);
|
||||
return $os;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract os name from path and validate it exists.
|
||||
*
|
||||
* @param $php_file
|
||||
* @return null|string
|
||||
*/
|
||||
function os_from_php($php_file)
|
||||
{
|
||||
$os = basename($php_file, '.inc.php');
|
||||
|
||||
if (file_exists("includes/definitions/$os.yaml")) {
|
||||
return $os;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the specified check and return the return value.
|
||||
* Make sure it isn't skipped by SKIP_TYPE_CHECK env variable and hasn't been run already
|
||||
*
|
||||
* @param string $type type of check lint, style, or unit
|
||||
* @param bool $passthru display the output as comes in
|
||||
* @param bool $command_only only display the intended command, no checks
|
||||
* @param array $options command specific options
|
||||
* @return int the return value from the check (0 = success)
|
||||
*/
|
||||
function run_check($type, $passthru, $command_only, $options = array())
|
||||
{
|
||||
global $completed_tests;
|
||||
if (getenv('SKIP_' . strtoupper($type) . '_CHECK') || $completed_tests[$type]) {
|
||||
echo ucfirst($type) . " check skipped.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
$function = 'check_' . $type;
|
||||
if (function_exists($function)) {
|
||||
$completed_tests[$type] = true;
|
||||
return $function($passthru, $command_only, $options);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs php -l and tests for any syntax errors
|
||||
*
|
||||
* @param bool $passthru display the output as comes in
|
||||
* @param bool $command_only only display the intended command, no checks
|
||||
* @return int the return value from running php -l (0 = success)
|
||||
*/
|
||||
function check_lint($passthru = false, $command_only = false)
|
||||
{
|
||||
$parallel_lint_bin = check_exec('parallel-lint');
|
||||
|
||||
// matches a substring of the relative path, leading / is treated as absolute path
|
||||
$lint_excludes = array('vendor/');
|
||||
|
||||
|
||||
$lint_exclude = build_excludes('--exclude ', $lint_excludes);
|
||||
$lint_cmd = "$parallel_lint_bin $lint_exclude ./";
|
||||
|
||||
if ($command_only) {
|
||||
echo $lint_cmd . PHP_EOL;
|
||||
return 250;
|
||||
}
|
||||
|
||||
echo 'Running lint check... ';
|
||||
|
||||
if ($passthru) {
|
||||
echo PHP_EOL;
|
||||
passthru($lint_cmd, $lint_ret);
|
||||
} else {
|
||||
exec($lint_cmd, $lint_output, $lint_ret);
|
||||
|
||||
if ($lint_ret > 0) {
|
||||
print(implode(PHP_EOL, $lint_output) . PHP_EOL);
|
||||
} else {
|
||||
echo "success\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $lint_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs phpcs --standard=PSR2 against the code base
|
||||
*
|
||||
* @param bool $passthru display the output as comes in
|
||||
* @param bool $command_only only display the intended command, no checks
|
||||
* @return int the return value from phpcs (0 = success)
|
||||
*/
|
||||
function check_style($passthru = false, $command_only = false)
|
||||
{
|
||||
$phpcs_bin = check_exec('phpcs');
|
||||
|
||||
$cs_cmd = "$phpcs_bin -n -p --colors --extensions=php --standard=misc/phpcs_librenms.xml ./";
|
||||
|
||||
if ($command_only) {
|
||||
echo $cs_cmd . PHP_EOL;
|
||||
return 250;
|
||||
}
|
||||
|
||||
echo 'Running style check... ';
|
||||
|
||||
if ($passthru) {
|
||||
echo PHP_EOL;
|
||||
passthru($cs_cmd, $cs_ret);
|
||||
} else {
|
||||
exec($cs_cmd, $cs_output, $cs_ret);
|
||||
|
||||
if ($cs_ret > 0) {
|
||||
echo "failed\n";
|
||||
print(implode(PHP_EOL, $cs_output) . PHP_EOL);
|
||||
} else {
|
||||
echo "success\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $cs_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs phpunit
|
||||
*
|
||||
* @param bool $passthru display the output as comes in
|
||||
* @param bool $command_only only display the intended command, no checks
|
||||
* @param array $options Supported: fail_fast, os, module
|
||||
* @return int the return value from phpunit (0 = success)
|
||||
*/
|
||||
function check_unit($passthru = false, $command_only = false, $options = array())
|
||||
{
|
||||
echo 'Running unit tests... ';
|
||||
|
||||
$phpunit_bin = check_exec('phpunit');
|
||||
|
||||
$phpunit_cmd = "$phpunit_bin --colors=always";
|
||||
|
||||
if ($options['fail_fast']) {
|
||||
$phpunit_cmd .= ' --stop-on-error --stop-on-failure';
|
||||
}
|
||||
|
||||
if ($options['os']) {
|
||||
$filter = implode('.*|', (array)$options['os']);
|
||||
// include tests that don't have data providers and only data sets that match
|
||||
$phpunit_cmd .= " --group os --filter '/::test[A-Za-z]+$|::test[A-Za-z]+ with data set \"$filter.*\"$/'";
|
||||
}
|
||||
|
||||
if ($options['docs_only']) {
|
||||
$phpunit_cmd .= " --group docs";
|
||||
}
|
||||
|
||||
if ($options['module']) {
|
||||
$phpunit_cmd .= ' tests/OSModulesTest.php';
|
||||
}
|
||||
|
||||
if ($command_only) {
|
||||
echo $phpunit_cmd . PHP_EOL;
|
||||
return 250;
|
||||
}
|
||||
|
||||
if ($passthru) {
|
||||
echo PHP_EOL;
|
||||
passthru($phpunit_cmd, $phpunit_ret);
|
||||
} else {
|
||||
exec($phpunit_cmd, $phpunit_output, $phpunit_ret);
|
||||
|
||||
if ($phpunit_ret > 0) {
|
||||
echo "failed\n";
|
||||
echo implode(PHP_EOL, $phpunit_output) . PHP_EOL;
|
||||
echo 'snmpsimd: output at /tmp/snmpsimd.log';
|
||||
} else {
|
||||
echo "success\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $phpunit_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given options array contains any of the $opts specified
|
||||
*
|
||||
* @param array $options the array from getopt()
|
||||
* @param string ...$opts options to check for
|
||||
* @return bool If one of the specified options is set
|
||||
*/
|
||||
function check_opt($options, ...$opts)
|
||||
{
|
||||
foreach ($opts as $option) {
|
||||
if (isset($options[$option])) {
|
||||
if ($options[$option] === false) {
|
||||
// no data, return that option is enabled
|
||||
return true;
|
||||
}
|
||||
return $options[$option];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list of exclude arguments from an array
|
||||
*
|
||||
* @param string $exclude_string such as "--exclude"
|
||||
* @param array $excludes array of directories to exclude
|
||||
* @return string resulting string
|
||||
*/
|
||||
function build_excludes($exclude_string, $excludes)
|
||||
{
|
||||
$result = '';
|
||||
foreach ($excludes as $exclude) {
|
||||
$result .= $exclude_string . $exclude . ' ';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for an executable and return the path to it
|
||||
* If it does not exist, run composer update.
|
||||
* If composer isn't installed, print error and exit.
|
||||
*
|
||||
* @param string $exec the name of the executable to check
|
||||
* @return string path to the executable
|
||||
*/
|
||||
function check_exec($exec)
|
||||
{
|
||||
$path = "vendor/bin/$exec";
|
||||
|
||||
if (is_executable($path)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
echo "Running composer install to install developer dependencies.\n";
|
||||
passthru("scripts/composer_wrapper.php install");
|
||||
|
||||
if (is_executable($path)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
echo "\nRunning installing deps with composer failed.\n You should try running './scripts/composer_wrapper.php install' by hand\n";
|
||||
echo "You can find more info at http://docs.librenms.org/Developing/Validating-Code/\n";
|
||||
exit(1);
|
||||
}
|
||||
echo "Use ./lnms dev:check\n";
|
||||
exit(1);
|
||||
|
282
tests/Unit/CiHelperTest.php
Normal file
282
tests/Unit/CiHelperTest.php
Normal file
@ -0,0 +1,282 @@
|
||||
<?php
|
||||
/**
|
||||
* CiHelperTest.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2020 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Tests\Unit;
|
||||
|
||||
use LibreNMS\Tests\TestCase;
|
||||
use LibreNMS\Util\CiHelper;
|
||||
|
||||
class CiHelperTest extends TestCase
|
||||
{
|
||||
public function testSetFlags()
|
||||
{
|
||||
$helper = new CiHelper();
|
||||
$allFalse = array_map(function ($flag) {
|
||||
return false;
|
||||
}, $this->getDefaultFlags());
|
||||
$allTrue = array_map(function ($flag) {
|
||||
return false;
|
||||
}, $this->getDefaultFlags());
|
||||
|
||||
$helper->setFlags($allFalse);
|
||||
$this->assertEquals($allFalse, $helper->getFlags());
|
||||
|
||||
$helper->setFlags($allTrue);
|
||||
$this->assertEquals($allTrue, $helper->getFlags());
|
||||
|
||||
$helper->setFlags(['undefined_flag' => false]);
|
||||
$this->assertEquals($allTrue, $helper->getFlags());
|
||||
|
||||
$helper->setFlags(['full' => false]);
|
||||
$testOne = $allTrue;
|
||||
$testOne['full'] = false;
|
||||
$this->assertEquals($testOne, $helper->getFlags());
|
||||
}
|
||||
|
||||
public function testDefaults()
|
||||
{
|
||||
$helper = new CiHelper();
|
||||
$this->assertEquals($this->getDefaultFlags(), $helper->getFlags());
|
||||
}
|
||||
|
||||
public function testNoFiles()
|
||||
{
|
||||
putenv('FILES=none');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip' => true,
|
||||
'style_skip' => true,
|
||||
'unit_skip' => true,
|
||||
'web_skip' => true,
|
||||
'lint_skip_php' => true,
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testSetOs()
|
||||
{
|
||||
$helper = new CiHelper();
|
||||
$helper->setOS(['netonix', 'e3meter']);
|
||||
$this->assertFlagsSet($helper, [
|
||||
'unit_os' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=none');
|
||||
$helper = new CiHelper();
|
||||
$helper->setOS(['netonix']);
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip' => true,
|
||||
'style_skip' => true,
|
||||
'web_skip' => true,
|
||||
'unit_os' => true,
|
||||
'lint_skip_php' => true,
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=includes/definitions/ios.yaml tests/data/fxos.json');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip' => true,
|
||||
'style_skip' => true,
|
||||
'web_skip' => true,
|
||||
'unit_os' => true,
|
||||
'lint_skip_php' => true,
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testSetModules()
|
||||
{
|
||||
$helper = new CiHelper();
|
||||
$helper->setModules(['sensors', 'processors']);
|
||||
$this->assertFlagsSet($helper, [
|
||||
'unit_modules' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=none');
|
||||
$helper = new CiHelper();
|
||||
$helper->setModules(['os']);
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip' => true,
|
||||
'style_skip' => true,
|
||||
'web_skip' => true,
|
||||
'unit_modules' => true,
|
||||
'lint_skip_php' => true,
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=none');
|
||||
$helper = new CiHelper();
|
||||
$helper->setOS(['linux']);
|
||||
$helper->setModules(['os']);
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip' => true,
|
||||
'style_skip' => true,
|
||||
'web_skip' => true,
|
||||
'unit_os' => true,
|
||||
'unit_modules' => true,
|
||||
'lint_skip_php' => true,
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=includes/definitions/ios.yaml tests/data/fxos.json');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip' => true,
|
||||
'style_skip' => true,
|
||||
'web_skip' => true,
|
||||
'unit_os' => true,
|
||||
'lint_skip_php' => true,
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=includes/definitions/ios.yaml tests/data/fxos.json');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip' => true,
|
||||
'style_skip' => true,
|
||||
'web_skip' => true,
|
||||
'unit_os' => true,
|
||||
'lint_skip_php' => true,
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function testFileCategorization()
|
||||
{
|
||||
putenv('FILES=LibreNMS/Alert/Transport/Sensu.php includes/services.inc.php');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=/daily.sh includes/services.inc.php');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip_python' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=daily.sh LibreNMS/__init__.py');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'style_skip' => true,
|
||||
'unit_skip' => true,
|
||||
'web_skip' => true,
|
||||
'lint_skip_php' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=includes/polling/sensors/ios.inc.php');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
'unit_os' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=html/images/os/ios.svg');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip' => true,
|
||||
'style_skip' => true,
|
||||
'web_skip' => true,
|
||||
'lint_skip_php' => true,
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
'unit_svg' => true,
|
||||
]);
|
||||
|
||||
putenv('FILES=html/images/os/ios.svg');
|
||||
$helper = new CiHelper();
|
||||
$helper->detectChangedFiles();
|
||||
$this->assertFlagsSet($helper, [
|
||||
'lint_skip' => true,
|
||||
'style_skip' => true,
|
||||
'web_skip' => true,
|
||||
'lint_skip_php' => true,
|
||||
'lint_skip_python' => true,
|
||||
'lint_skip_bash' => true,
|
||||
'unit_svg' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
private function assertFlagsSet(CiHelper $helper, $flags = [])
|
||||
{
|
||||
$full = $this->getDefaultFlags();
|
||||
foreach ($flags as $name => $value) {
|
||||
$full[$name] = $value;
|
||||
$this->assertEquals($value, $helper->getFlag($name), "Flag $name incorrect.");
|
||||
}
|
||||
|
||||
$this->assertEquals($full, $helper->getFlags());
|
||||
}
|
||||
|
||||
private function getDefaultFlags()
|
||||
{
|
||||
return [
|
||||
'lint_enable' => true,
|
||||
'style_enable' => true,
|
||||
'unit_enable' => true,
|
||||
'web_enable' => false,
|
||||
'lint_skip' => false,
|
||||
'style_skip' => false,
|
||||
'unit_skip' => false,
|
||||
'web_skip' => false,
|
||||
'lint_skip_php' => false,
|
||||
'lint_skip_python' => false,
|
||||
'lint_skip_bash' => false,
|
||||
'unit_os' => false,
|
||||
'unit_docs' => false,
|
||||
'unit_svg' => false,
|
||||
'unit_modules' => false,
|
||||
'docs_changed' => false,
|
||||
'ci' => false,
|
||||
'commands' => false,
|
||||
'fail-fast' => false,
|
||||
'full' => false,
|
||||
'quiet' => false,
|
||||
];
|
||||
}
|
||||
}
|
232
tests/Unit/FileCategorizerTest.php
Normal file
232
tests/Unit/FileCategorizerTest.php
Normal file
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
/**
|
||||
* FileCategorizerTest.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2020 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Tests\Unit;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use LibreNMS\Tests\TestCase;
|
||||
use LibreNMS\Util\FileCategorizer;
|
||||
|
||||
class FileCategorizerTest extends TestCase
|
||||
{
|
||||
public function testEmptyFiles()
|
||||
{
|
||||
$cat = new FileCategorizer();
|
||||
$this->assertEquals($this->getCategorySkeleton(), $cat->categorize());
|
||||
}
|
||||
|
||||
public function testIgnoredFiles()
|
||||
{
|
||||
$this->assertCategorized([], [
|
||||
'docs/Nothing.md',
|
||||
'none',
|
||||
'includes/something.yaml',
|
||||
'html/test.css',
|
||||
'falsepythonpy',
|
||||
'falsephp',
|
||||
'falsebash',
|
||||
'resource',
|
||||
'vendor/misc/composer.lock',
|
||||
'/mibs/3com',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testPhpFiles()
|
||||
{
|
||||
$this->assertCategorized([
|
||||
'php' => [
|
||||
'includes/polling/sensors.inc.php',
|
||||
'misc/test.php',
|
||||
'app/Http/Kernel.php',
|
||||
'LibreNMS/Modules/Mpls.php'
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testDocsFiles()
|
||||
{
|
||||
$this->assertCategorized([
|
||||
'docs' => [
|
||||
'doc/CNAME',
|
||||
'doc/Developing/Creating-Release.md',
|
||||
'mkdocs.yml',
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function testPython()
|
||||
{
|
||||
$this->assertCategorized([
|
||||
'python' => [
|
||||
'python.py',
|
||||
'LibreNMS/__init__.py',
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function testBash()
|
||||
{
|
||||
$this->assertCategorized([
|
||||
'bash' => [
|
||||
'daily.sh',
|
||||
'scripts/deploy-docs.sh',
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function testSvg()
|
||||
{
|
||||
$this->assertCategorized([
|
||||
'svg' => [
|
||||
'html/images/os/zte.svg',
|
||||
'html/images/logos/zyxel.svg',
|
||||
'html/svg/403.svg'
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function testResources()
|
||||
{
|
||||
$this->assertCategorized([
|
||||
'resources' => [
|
||||
'resources/js/app.js',
|
||||
'resources/js/components/LibrenmsSetting.vue',
|
||||
'resources/views/layouts/librenmsv1.blade.php'
|
||||
],
|
||||
'php' => [
|
||||
'resources/views/layouts/librenmsv1.blade.php'
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function testOsFiles()
|
||||
{
|
||||
$this->assertCategorized([
|
||||
'os' => ['ftd', '3com', 'adva_fsp150', 'saf-integra-b'],
|
||||
'os-files' => [
|
||||
'tests/data/ftd.json',
|
||||
'tests/data/3com_4200.json',
|
||||
'tests/data/adva_fsp150_ge114pro.json',
|
||||
'tests/data/saf-integra-b.json'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertCategorized([
|
||||
'os' => ['ciscowap', 'xos', 'ciscosb', 'linux'],
|
||||
'os-files' => [
|
||||
'tests/snmpsim/ciscowap.snmprec',
|
||||
'tests/snmpsim/xos_x480.snmprec',
|
||||
'tests/snmpsim/ciscosb_esw540_8p.snmprec',
|
||||
'tests/snmpsim/linux_fbsd-nfs-client-v1.snmprec'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertCategorized([
|
||||
'os' => ['arris-c4', 'ios'],
|
||||
'os-files' => [
|
||||
'includes/discovery/sensors/temperature/arris-c4.inc.php',
|
||||
'includes/polling/entity-physical/ios.inc.php'
|
||||
],
|
||||
'php' => [
|
||||
'includes/discovery/sensors/temperature/arris-c4.inc.php',
|
||||
'includes/polling/entity-physical/ios.inc.php'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertCategorized([
|
||||
'os' => ['3com', 'arris-dsr4410md', 'adva_fsp3kr7', 'xirrus_aos'],
|
||||
'os-files' => [
|
||||
'LibreNMS/OS/ThreeCom.php',
|
||||
'LibreNMS/OS/ArrisDsr4410md.php',
|
||||
'LibreNMS/OS/AdvaFsp3kr7.php',
|
||||
'LibreNMS/OS/XirrusAos.php',
|
||||
],
|
||||
'php' => [
|
||||
'LibreNMS/OS/ThreeCom.php',
|
||||
'LibreNMS/OS/ArrisDsr4410md.php',
|
||||
'LibreNMS/OS/AdvaFsp3kr7.php',
|
||||
'LibreNMS/OS/XirrusAos.php',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertCategorized([
|
||||
'os' => ['dlink', 'eltex-olt'],
|
||||
'os-files' => [
|
||||
'includes/definitions/dlink.yaml',
|
||||
'includes/definitions/discovery/eltex-olt.yaml',
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
public function testFullChecks()
|
||||
{
|
||||
$this->assertCategorized(['full-checks' => ['composer.lock']]);
|
||||
$this->assertCategorized(['full-checks' => ['.travis.yml']], ['other', '.travis.yml']);
|
||||
|
||||
$this->assertCategorized([
|
||||
'os' => ['3com', 'calix', 'ptp650', 'dd-wrt', 'arista_eos'],
|
||||
'os-files' => [
|
||||
'tests/data/3com.json',
|
||||
'tests/snmpsim/calix.snmprec',
|
||||
'LibreNMS/OS/Ptp650.php',
|
||||
'includes/definitions/dd-wrt.yaml',
|
||||
'includes/definitions/discovery/arista_eos.yaml',
|
||||
],
|
||||
'php' => [
|
||||
'LibreNMS/OS/Ptp650.php'
|
||||
],
|
||||
'full-checks' => [true]
|
||||
], [
|
||||
'tests/data/3com.json',
|
||||
'tests/snmpsim/calix.snmprec',
|
||||
'LibreNMS/OS/Ptp650.php',
|
||||
'includes/definitions/dd-wrt.yaml',
|
||||
'includes/definitions/discovery/arista_eos.yaml',
|
||||
]);
|
||||
}
|
||||
|
||||
private function assertCategorized($expected, $input = null, $message = '')
|
||||
{
|
||||
$files = $input ?? array_unique(Arr::flatten(Arr::except($expected, ['os']))); // os is a virtual category
|
||||
$expected = array_merge($this->getCategorySkeleton(), $expected);
|
||||
|
||||
$this->assertEquals($expected, (new FileCategorizer($files))->categorize(), $message);
|
||||
}
|
||||
|
||||
private function getCategorySkeleton()
|
||||
{
|
||||
return [
|
||||
'php' => [],
|
||||
'docs' => [],
|
||||
'python' => [],
|
||||
'bash' => [],
|
||||
'svg' => [],
|
||||
'resources' => [],
|
||||
'full-checks' => [],
|
||||
'os-files' => [],
|
||||
'os' => [],
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user