Replace outdated test setup code with composer.json (#5445)
Some checks failed
L10n Update / update (push) Has been cancelled
PHP Tests / Static analysis for php 8.2 on ubuntu-latest (push) Has been cancelled
PHP Tests / Static analysis for php 8.3 on ubuntu-latest (push) Has been cancelled
PHP Tests / Static analysis for php 8.4 on ubuntu-latest (push) Has been cancelled
PHP Tests / Unit tests with php 8.2 on ubuntu-latest (push) Has been cancelled
PHP Tests / Unit tests with php 8.3 on ubuntu-latest (push) Has been cancelled
PHP Tests / Unit tests with php 8.4 on ubuntu-latest (push) Has been cancelled

This is preparation for a GitHub action to streamline tests, which
* expects the `phpunit.xml` configuration at the root level, and
* installs dependencies via `composer`.

Proof that the same number of tests are run after moving the
configuration file:
*
[main](https://github.com/Icinga/icingaweb2/actions/runs/18972121136/job/54182208796#step:6:243)
* [this
PR](https://github.com/Icinga/icingaweb2/actions/runs/19137281980/job/54692472598#step:6:243)

Rationale for introducing `composer`:

GitHub Actions for this repository and any other module that requires
Mockery must specify this dependency themselves. Module tests require
Icinga Web anyway, so all (development) dependencies and any changes to
them should be automatically applied instead of having to adjust each
individual module affected. If we eventually upload our library bundles
to Packagist as well, we could also specify them in `composer.json` once
instead of having to require them in every action.
This commit is contained in:
Eric Lippmann 2025-12-05 15:17:37 +01:00 committed by GitHub
commit 3b732c3ff9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 118 additions and 350 deletions

6
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: composer
directory: /
schedule:
interval: daily

View file

@ -98,9 +98,8 @@ jobs:
- name: Setup dependencies
run: |
composer init -n --require mockery/mockery:* --require ipl/i18n:@dev --require ipl/web:@dev
composer config platform.php 8.2
composer install -n --no-progress
composer require --no-install ipl/i18n:@dev ipl/web:@dev
composer install --no-progress
git clone --depth 1 --branch snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git vendor/icinga-php-thirdparty
- name: PHPUnit
@ -108,4 +107,4 @@ jobs:
ICINGAWEB_TEST_MYSQL_PORT: ${{ job.services.mysql.ports['3306'] }}
ICINGAWEB_TEST_PGSQL_PORT: ${{ job.services.pgsql.ports['5432'] }}
ICINGAWEB_LIBDIR: vendor/
run: phpunit -c modules/test/phpunit.xml --verbose
run: phpunit --verbose

8
.gitignore vendored
View file

@ -3,12 +3,8 @@
# Except those related to git
!.git*
!.travis.yml
!.mailmap
# Testing - created by test/setup_vendor.sh
/vendor/
# Exclude application log files
var/log/*
@ -20,3 +16,7 @@ build/*
# Exclude dompdf font cache
library/vendor/dompdf/lib/fonts/*.php
library/vendor/dompdf/lib/fonts/log.htm
# Exclude files from composer install
vendor/
composer.lock

10
composer.json Normal file
View file

@ -0,0 +1,10 @@
{
"config": {
"platform": {
"php": "8.2"
}
},
"require-dev": {
"mockery/mockery": "^1.6"
}
}

View file

@ -292,22 +292,5 @@ namespace Icinga\Test {
$adapter->exec('DROP TABLE ' . $table . ';');
}
}
/**
* Add assertMatchesRegularExpression() method for phpunit >= 8.0 < 9.0 for compatibility with PHP 7.2.
*
* @TODO Remove once PHP 7.2 support is not needed for testing anymore.
*/
public static function assertMatchesRegularExpression(
string $pattern,
string $string,
string $message = ''
): void {
if (method_exists(parent::class, 'assertMatchesRegularExpression')) {
parent::assertMatchesRegularExpression($pattern, $string, $message);
} else {
static::assertRegExp($pattern, $string, $message);
}
}
}
}

View file

@ -1,95 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit bootstrap="../../test/php/bootstrap.php">
<testsuites>
<!--
Unit testing
-->
<testsuite name="unit-framework">
<directory>../../test/php/application/</directory>
<directory>../../test/php/library/</directory>
</testsuite>
<!-- Module tests are independent from core tests -->
<testsuite name="unit-modules">
<directory>../*/test/php</directory>
<exclude>../*/test/php/regression</exclude>
</testsuite>
<!--
Regression testing
-->
<testsuite name="regression-framework">
<directory>../../test/php/regression/</directory>
</testsuite>
<!-- Module tests are independent from core tests -->
<testsuite name="regression-modules">
<directory>../*/test/php/regression</directory>
</testsuite>
</testsuites>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">../../application</directory>
<directory suffix=".php">../../library/Icinga</directory>
<directory suffix=".php">../../modules</directory>
<exclude>
<!-- application/clicommands -->
<directory suffix=".php">../../application/clicommands</directory>
<!-- application/controllers -->
<directory suffix=".php">../../application/controllers</directory>
<!-- application/forms -->
<file>../../application/forms/Config/GeneralForm.php</file>
<file>../../application/forms/Config/LoggingForm.php</file>
<file>../../application/forms/Config/ConfirmRemovalForm.php</file>
<directory suffix=".php">../../application/forms/Authentication</directory>
<directory suffix=".php">../../application/forms/Dashboard</directory>
<directory suffix=".php">../../application/forms/Preference</directory>
<!-- application/views -->
<file>../../application/views/helpers/FormNumber.php</file>
<file>../../application/views/helpers/FormDateTime.php</file>
<!-- library/Icinga/Logger -->
<file>../../library/Icinga/Logger/Writer/SyslogWriter.php</file>
<!-- library/Icinga/User -->
<file>../../library/Icinga/User/Message.php</file>
<!-- library/Icinga/Application -->
<file>../../library/Icinga/Application/ApplicationBootstrap.php</file>
<file>../../library/Icinga/Application/Benchmark.php</file>
<file>../../library/Icinga/Application/Cli.php</file>
<file>../../library/Icinga/Application/EmbeddedWeb.php</file>
<file>../../library/Icinga/Application/LegacyWeb.php</file>
<file>../../library/Icinga/Application/Platform.php</file>
<file>../../library/Icinga/Application/Web.php</file>
<file>../../library/Icinga/Application/functions.php</file>
<file>../../library/Icinga/Application/webrouter.php</file>
<!-- library/Icinga/Web -->
<file>../../library/Icinga/Web/JavaScript.php</file>
<file>../../library/Icinga/Web/LessCompiler.php</file>
<file>../../library/Icinga/Web/Request.php</file>
<file>../../library/Icinga/Web/Response.php</file>
<file>../../library/Icinga/Web/Session.php</file>
<file>../../library/Icinga/Web/StyleSheet.php</file>
<file>../../library/Icinga/Web/View.php</file>
<file>../../library/Icinga/Web/ViewStream.php</file>
<file>../../library/Icinga/Web/Widget.php</file>
<!-- library/Icinga/Web/Widget -->
<file>../../library/Icinga/Web/Widget/AbstractWidget.php</file>
<file>../../library/Icinga/Web/Widget/AlertMessageBox.php</file>
<file>../../library/Icinga/Web/Widget/SortBox.php</file>
<directory suffix=".php">../../library/Icinga/Web/Widget/Chart</directory>
<directory suffix=".php">../../library/Icinga/Web/Widget/Tabextension</directory>
<!-- library/Icinga/Web/Hook -->
<file>../../library/Icinga/Web/Hook/Ticket.php</file>
<file>../../library/Icinga/Web/Hook/Grapher.php</file>
<!-- library/Icinga/Web/Controller -->
<directory suffix=".php">../../library/Icinga/Web/Controller</directory>
<!-- library/Icinga/Web/Form -->
<directory suffix=".php">../../library/Icinga/Web/Form/Decorator</directory>
<!-- library/Icinga/Web/View -->
<directory suffix=".php">../../library/Icinga/Web/View/helpers</directory>
</exclude>
</whitelist>
</filter>
<listeners>
<listener class="\Mockery\Adapter\Phpunit\TestListener"></listener>
</listeners>
</phpunit>

95
phpunit.xml Normal file
View file

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit bootstrap="test/php/bootstrap.php">
<testsuites>
<!--
Unit testing
-->
<testsuite name="unit-framework">
<directory>test/php/application/</directory>
<directory>test/php/library/</directory>
</testsuite>
<!-- Module tests are independent from core tests -->
<testsuite name="unit-modules">
<directory>modules/*/test/php</directory>
<exclude>modules/*/test/php/regression</exclude>
</testsuite>
<!--
Regression testing
-->
<testsuite name="regression-framework">
<directory>test/php/regression/</directory>
</testsuite>
<!-- Module tests are independent from core tests -->
<testsuite name="regression-modules">
<directory>modules/*/test/php/regression</directory>
</testsuite>
</testsuites>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">application</directory>
<directory suffix=".php">library/Icinga</directory>
<directory suffix=".php">modules</directory>
<exclude>
<!-- application/clicommands -->
<directory suffix=".php">application/clicommands</directory>
<!-- application/controllers -->
<directory suffix=".php">application/controllers</directory>
<!-- application/forms -->
<file>application/forms/Config/GeneralForm.php</file>
<file>application/forms/Config/LoggingForm.php</file>
<file>application/forms/Config/ConfirmRemovalForm.php</file>
<directory suffix=".php">application/forms/Authentication</directory>
<directory suffix=".php">application/forms/Dashboard</directory>
<directory suffix=".php">application/forms/Preference</directory>
<!-- application/views -->
<file>application/views/helpers/FormNumber.php</file>
<file>application/views/helpers/FormDateTime.php</file>
<!-- library/Icinga/Logger -->
<file>library/Icinga/Logger/Writer/SyslogWriter.php</file>
<!-- library/Icinga/User -->
<file>library/Icinga/User/Message.php</file>
<!-- library/Icinga/Application -->
<file>library/Icinga/Application/ApplicationBootstrap.php</file>
<file>library/Icinga/Application/Benchmark.php</file>
<file>library/Icinga/Application/Cli.php</file>
<file>library/Icinga/Application/EmbeddedWeb.php</file>
<file>library/Icinga/Application/LegacyWeb.php</file>
<file>library/Icinga/Application/Platform.php</file>
<file>library/Icinga/Application/Web.php</file>
<file>library/Icinga/Application/functions.php</file>
<file>library/Icinga/Application/webrouter.php</file>
<!-- library/Icinga/Web -->
<file>library/Icinga/Web/JavaScript.php</file>
<file>library/Icinga/Web/LessCompiler.php</file>
<file>library/Icinga/Web/Request.php</file>
<file>library/Icinga/Web/Response.php</file>
<file>library/Icinga/Web/Session.php</file>
<file>library/Icinga/Web/StyleSheet.php</file>
<file>library/Icinga/Web/View.php</file>
<file>library/Icinga/Web/ViewStream.php</file>
<file>library/Icinga/Web/Widget.php</file>
<!-- library/Icinga/Web/Widget -->
<file>library/Icinga/Web/Widget/AbstractWidget.php</file>
<file>library/Icinga/Web/Widget/AlertMessageBox.php</file>
<file>library/Icinga/Web/Widget/SortBox.php</file>
<directory suffix=".php">library/Icinga/Web/Widget/Chart</directory>
<directory suffix=".php">library/Icinga/Web/Widget/Tabextension</directory>
<!-- library/Icinga/Web/Hook -->
<file>library/Icinga/Web/Hook/Ticket.php</file>
<file>library/Icinga/Web/Hook/Grapher.php</file>
<!-- library/Icinga/Web/Controller -->
<directory suffix=".php">library/Icinga/Web/Controller</directory>
<!-- library/Icinga/Web/Form -->
<directory suffix=".php">library/Icinga/Web/Form/Decorator</directory>
<!-- library/Icinga/Web/View -->
<directory suffix=".php">library/Icinga/Web/View/helpers</directory>
</exclude>
</whitelist>
</filter>
<listeners>
<listener class="\Mockery\Adapter\Phpunit\TestListener"></listener>
</listeners>
</phpunit>

View file

@ -1,145 +0,0 @@
#!/usr/bin/env php
<?php
function findPhpFiles($dir, &$files = [])
{
if (substr($dir, -1, 1) !== DIRECTORY_SEPARATOR) {
$dir .= DIRECTORY_SEPARATOR;
}
if ($dh = opendir($dir)) {
while (($name = readdir($dh)) !== false) {
$path = $dir . $name;
if (substr($name, 0, 1) === '.') {
continue;
} elseif (is_file($path) && preg_match('~\.ph(p|tml)$~i', $path)) {
$files[] = $path;
} elseif (is_dir($path)) {
findPhpFiles($path, $files);
}
}
closedir($dh);
return $files;
} else {
throw new Exception('Could not read directory: ' . $dir);
}
}
function stdout($t, $color = '32')
{
if (posix_isatty(STDOUT) && $color) {
$t = "\e[${color}m" . $t . "\e[39m";
}
fwrite(STDOUT, $t);
}
function stderr($t)
{
if (posix_isatty(STDERR)) {
$t = "\e[91m" . $t . "\e[39m";
}
fwrite(STDERR, $t);
}
function checkFile($path, &$errors)
{
$escapedPath = escapeshellarg($path);
exec("php -l ${escapedPath} 2>&1 >/dev/null", $output, $rc);
if (! empty($output) || $rc != 0) {
stdout('E', '91');
foreach ($output as $line) {
// remove own name from text
$line = preg_replace('~ in ' . preg_quote($path) . '~i', '', $line);
$errors[$path][] = $line;
}
} else {
stdout('.');
}
}
function usage()
{
printf("Usage: %s [--verbose] [--exclude file-regex] [path]\n\n", $_SERVER['argv'][0]);
}
function main($argv)
{
$fileCount = 0;
$verbose = false;
$errors = [];
$excludes = [];
$searchPaths = [];
for ($i = 1; $i < count($argv); $i++) {
$arg = $argv[$i];
switch ($arg) {
case '-h':
case '--help':
usage();
return 1;
case '-v':
case '--verbose':
$verbose = true;
break;
case '-e':
case '--exclude':
$excludes[] = $argv[++$i];
break;
default:
if (substr($arg, 0, 1) === '-') {
stderr("Unknown argument: $arg");
return 1;
} else {
$searchPaths[] = $arg;
}
}
}
if (empty($searchPaths)) {
$searchPaths = ['.'];
}
$files = [];
foreach ($searchPaths as $basePath) {
findPhpFiles($basePath, $files);
}
foreach ($files as $file) {
foreach ($excludes as $exclude) {
if (preg_match("~$exclude~", $file)) {
continue 2;
}
}
$fileCount++;
if ($verbose) {
printf("%s\n", $file);
}
checkFile($file, $errors);
}
$errorCount = count($errors);
if ($fileCount === 0) {
stderr("error: No files found!\n");
return 2;
} elseif ($errorCount > 0) {
stdout("\n");
foreach ($errors as $file => $errList) {
stderr("\n$file\n " . join("\n ", $errList) . "\n");
}
stderr(sprintf("\nFound syntax errors in %d of %d files! \n", $errorCount, $fileCount));
return 1;
} else {
stdout(sprintf("\n\nChecked %d files successfully! \n", $fileCount));
return 0;
}
}
exit(main($_SERVER['argv']));

View file

@ -1,73 +0,0 @@
#!/bin/bash
set -ex
ICINGAWEB_HOME=${ICINGAWEB_HOME:="$(dirname "$(readlink -f "$(dirname "$0")")")"}
PHPCS_VERSION=${PHPCS_VERSION:=3.5.3}
MOCKERY_VERSION=${MOCKERY_VERSION:=0.9.9}
HAMCREST_VERSION=${HAMCREST_VERSION:=2.0.0}
PHPUNIT_VERSION=${PHPUNIT_VERSION:=5.7}
cd "${ICINGAWEB_HOME}"
test -d vendor || mkdir vendor
cd vendor/
del_old_link() {
if [ -L "$1" ]; then
rm "$1"
fi
}
# phpunit
phpunit_path="phpunit-${PHPUNIT_VERSION}"
if [ ! -e "${phpunit_path}".phar ]; then
wget -O "${phpunit_path}".phar https://phar.phpunit.de/phpunit-${PHPUNIT_VERSION}.phar
fi
ln -svf "${phpunit_path}".phar phpunit.phar
del_old_link ../phpunit.phar
# phpcs
phpcs_path="phpcs-${PHPCS_VERSION}"
if [ ! -e "${phpcs_path}".phar ]; then
wget -O "${phpcs_path}".phar \
https://github.com/squizlabs/PHP_CodeSniffer/releases/download/${PHPCS_VERSION}/phpcs.phar
fi
ln -svf "${phpcs_path}".phar phpcs.phar
del_old_link ../phpcs.phar
phpcbf_path="phpcbf-${PHPCS_VERSION}"
if [ ! -e "${phpcbf_path}".phar ]; then
wget -O "${phpcbf_path}".phar \
https://github.com/squizlabs/PHP_CodeSniffer/releases/download/${PHPCS_VERSION}/phpcbf.phar
fi
ln -svf "${phpcbf_path}".phar phpcbf.phar
del_old_link ../phpcbf.phar
# mockery
mockery_path="mockery-${MOCKERY_VERSION}"
if [ ! -e "${mockery_path}".tar.gz ]; then
wget -O "${mockery_path}".tar.gz \
https://github.com/mockery/mockery/archive/${MOCKERY_VERSION}.tar.gz
fi
if [ ! -d "${mockery_path}" ]; then
tar xf "${mockery_path}".tar.gz
fi
ln -svf "${mockery_path}"/library/Mockery Mockery
ln -svf "${mockery_path}"/library/Mockery.php Mockery.php
del_old_link ../Mockery
del_old_link ../Mockery.php
# hamcrest
hamcrest_path="hamcrest-php-${HAMCREST_VERSION}"
if [ ! -e "${hamcrest_path}".tar.gz ]; then
wget -O "${hamcrest_path}".tar.gz \
https://github.com/hamcrest/hamcrest-php/archive/v${HAMCREST_VERSION}.tar.gz
fi
if [ ! -d "${hamcrest_path}" ]; then
tar xf "${hamcrest_path}".tar.gz
fi
ln -svf "${hamcrest_path}"/hamcrest/Hamcrest Hamcrest
ln -svf "${hamcrest_path}"/hamcrest/Hamcrest.php Hamcrest.php
del_old_link ../Hamcrest
del_old_link ../Hamcrest.php

View file

@ -1 +0,0 @@
extension=ldap.so

View file

@ -1,11 +0,0 @@
#!/bin/bash
set -ex
mysql -u root -e "GRANT ALL ON *.* TO icinga_unittest@localhost IDENTIFIED BY 'icinga_unittest'"
export PGHOST=localhost
export PGUSER=postgres
psql -c "CREATE USER icinga_unittest WITH PASSWORD 'icinga_unittest'"
psql -c "CREATE DATABASE icinga_unittest WITH OWNER icinga_unittest"