From 8ca6cc32b2c789a3149861159ad258f2cb9491e3 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 14:39:39 +0200 Subject: Adding upstream version 2.11.4. Signed-off-by: Daniel Baumann --- library/Icinga/Test/BaseTestCase.php | 361 +++++++++++++++++++++++++++++++++++ library/Icinga/Test/ClassLoader.php | 113 +++++++++++ library/Icinga/Test/DbTest.php | 47 +++++ 3 files changed, 521 insertions(+) create mode 100644 library/Icinga/Test/BaseTestCase.php create mode 100644 library/Icinga/Test/ClassLoader.php create mode 100644 library/Icinga/Test/DbTest.php (limited to 'library/Icinga/Test') diff --git a/library/Icinga/Test/BaseTestCase.php b/library/Icinga/Test/BaseTestCase.php new file mode 100644 index 0000000..6702df0 --- /dev/null +++ b/library/Icinga/Test/BaseTestCase.php @@ -0,0 +1,361 @@ + array( + 'type' => 'db', + 'db' => 'mysql', + 'host' => '127.0.0.1', + 'port' => 3306, + 'dbname' => 'icinga_unittest', + 'username' => 'icinga_unittest', + 'password' => 'icinga_unittest' + ), + 'pgsql' => array( + 'type' => 'db', + 'db' => 'pgsql', + 'host' => '127.0.0.1', + 'port' => 5432, + 'dbname' => 'icinga_unittest', + 'username' => 'icinga_unittest', + 'password' => 'icinga_unittest' + ), + ); + + /** + * Setup the default timezone + */ + public static function setupTimezone() + { + date_default_timezone_set('UTC'); + } + + /** + * Setup test path environment + * + * @throws RuntimeException + */ + public static function setupDirectories() + { + $baseDir = getenv('ICINGAWEB_BASEDIR') ?: realpath(__DIR__ . '/../../../'); + if ($baseDir === false) { + throw new RuntimeException('Application base dir not found'); + } + + $libDir = getenv('ICINGAWEB_ICINGA_LIB') ?: realpath($baseDir . '/library/Icinga'); + if ($libDir === false) { + throw new RuntimeException('Icinga library dir not found'); + } + + self::$appDir = $baseDir . '/application'; + self::$libDir = $libDir; + self::$etcDir = $baseDir . '/etc'; + self::$testDir = $baseDir . '/test/php'; + self::$shareDir = $baseDir . '/share/icinga2-web'; + self::$moduleDir = getenv('ICINGAWEB_MODULES_DIR') ?: $baseDir . '/modules'; + } + + /** + * Setup MVC bootstrapping and ensure that the Icinga-Mock gets reinitialized + */ + public function setUp(): void + { + parent::setUp(); + + StaticTranslator::$instance = new NoopTranslator(); + $this->setupIcingaMock(); + } + + /** + * Setup mock object for the application's bootstrap + * + * @return Mockery\Mock + */ + protected function setupIcingaMock() + { + $requestMock = Mockery::mock('Icinga\Web\Request')->shouldDeferMissing(); + $requestMock->shouldReceive('getPathInfo')->andReturn('')->byDefault() + ->shouldReceive('getBaseUrl')->andReturn('/')->byDefault() + ->shouldReceive('getQuery')->andReturn(array())->byDefault() + ->shouldReceive('getParam')->with(Mockery::type('string'), Mockery::type('string')) + ->andReturnUsing(function ($name, $default) { + return $default; + })->byDefault(); + + $responseMock = Mockery::mock('Icinga\Web\Response')->shouldDeferMissing(); + // Can't express this as demeter chains. See: https://github.com/padraic/mockery/issues/59 + $bootstrapMock = Mockery::mock('Icinga\Application\ApplicationBootstrap')->shouldDeferMissing(); + $libDir = dirname(self::$libDir); + $bootstrapMock->shouldReceive('getFrontController')->andReturn($bootstrapMock) + ->shouldReceive('getApplicationDir')->andReturn(self::$appDir) + ->shouldReceive('getLibraryDir')->andReturnUsing(function ($subdir = null) use ($libDir) { + if ($subdir !== null) { + $libDir .= '/' . ltrim($subdir, '/'); + } + return $libDir; + }) + ->shouldReceive('getRequest')->andReturn($requestMock) + ->shouldReceive('getResponse')->andReturn($responseMock); + + Icinga::setApp($bootstrapMock, true); + return $bootstrapMock; + } + + /** + * Return the currently active request mock object + * + * @return Icinga\Web\Request + */ + public function getRequestMock() + { + return Icinga::app()->getRequest(); + } + + /** + * Return the currently active response mock object + * + * @return Icinga\Web\Response + */ + public function getResponseMock() + { + return Icinga::app()->getFrontController()->getResponse(); + } + + /** + * Create Config for database configuration + * + * @param string $name + * + * @return ConfigObject + * @throws RuntimeException + */ + protected function createDbConfigFor($name) + { + if (array_key_exists($name, self::$dbConfiguration)) { + $config = new ConfigObject(self::$dbConfiguration[$name]); + + $host = getenv(sprintf('ICINGAWEB_TEST_%s_HOST', strtoupper($name))); + if ($host) { + $config['host'] = $host; + } + + $port = getenv(sprintf('ICINGAWEB_TEST_%s_PORT', strtoupper($name))); + if ($port) { + $config['port'] = $port; + } + + return $config; + } + + throw new RuntimeException('Configuration for database type not available: ' . $name); + } + + /** + * Creates an array of Icinga\Data\Db\DbConnection + * + * @param string $name + * + * @return array + */ + protected function createDbConnectionFor($name) + { + try { + $conn = ResourceFactory::createResource($this->createDbConfigFor($name)); + } catch (Exception $e) { + $conn = $e->getMessage(); + } + + return array( + array($conn) + ); + } + + /** + * PHPUnit provider for mysql + * + * @return DbConnection + */ + public function mysqlDb() + { + return $this->createDbConnectionFor('mysql'); + } + + /** + * PHPUnit provider for pgsql + * + * @return DbConnection + */ + public function pgsqlDb() + { + return $this->createDbConnectionFor('pgsql'); + } + + /** + * PHPUnit provider for oracle + * + * @return DbConnection + */ + public function oracleDb() + { + return $this->createDbConnectionFor('oracle'); + } + + /** + * Executes sql file by using the database connection + * + * @param DbConnection $resource + * @param string $filename + * + * @throws RuntimeException + */ + public function loadSql(DbConnection $resource, $filename) + { + if (!is_file($filename)) { + throw new RuntimeException( + 'Sql file not found: ' . $filename . ' (test=' . $this->getName() . ')' + ); + } + + $sqlData = file_get_contents($filename); + + if (!$sqlData) { + throw new RuntimeException( + 'Sql file is empty: ' . $filename . ' (test=' . $this->getName() . ')' + ); + } + + $resource->getDbAdapter()->exec($sqlData); + } + + /** + * Setup provider for testcase + * + * @param string|DbConnection|null $resource + */ + public function setupDbProvider($resource) + { + if (!$resource instanceof DbConnection) { + if (is_string($resource)) { + $this->markTestSkipped('Could not initialize provider: ' . $resource); + } else { + $this->markTestSkipped('Could not initialize provider'); + } + return; + } + + $adapter = $resource->getDbAdapter(); + + try { + $adapter->getConnection(); + } catch (Exception $e) { + $this->markTestSkipped('Could not connect to provider: '. $e->getMessage()); + } + + $tables = $adapter->listTables(); + foreach ($tables as $table) { + $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); + } + } + } + + BaseTestCase::setupTimezone(); + BaseTestCase::setupDirectories(); +} diff --git a/library/Icinga/Test/ClassLoader.php b/library/Icinga/Test/ClassLoader.php new file mode 100644 index 0000000..af90a7e --- /dev/null +++ b/library/Icinga/Test/ClassLoader.php @@ -0,0 +1,113 @@ +namespaces[$namespace] = $directory; + + return $this; + } + + /** + * Test whether a namespace exists + * + * @param string $namespace + * + * @return bool + */ + public function hasNamespace($namespace) + { + return array_key_exists($namespace, $this->namespaces); + } + + /** + * Get the source file of the given class or interface + * + * @param string $class Name of the class or interface + * + * @return string|null + */ + public function getSourceFile($class) + { + foreach ($this->namespaces as $namespace => $dir) { + if ($class === strstr($class, $namespace)) { + $classPath = str_replace( + self::NAMESPACE_SEPARATOR, + DIRECTORY_SEPARATOR, + substr($class, strlen($namespace)) + ) . '.php'; + if (file_exists($file = $dir . $classPath)) { + return $file; + } + } + } + return null; + } + + /** + * Load the given class or interface + * + * @param string $class Name of the class or interface + * + * @return bool Whether the class or interface has been loaded + */ + public function loadClass($class) + { + if ($file = $this->getSourceFile($class)) { + require $file; + return true; + } + return false; + } + + /** + * Register {@link loadClass()} as an autoloader + */ + public function register() + { + spl_autoload_register(array($this, 'loadClass')); + } + + /** + * Unregister {@link loadClass()} as an autoloader + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Unregister this as an autoloader + */ + public function __destruct() + { + $this->unregister(); + } +} diff --git a/library/Icinga/Test/DbTest.php b/library/Icinga/Test/DbTest.php new file mode 100644 index 0000000..d1b1ff0 --- /dev/null +++ b/library/Icinga/Test/DbTest.php @@ -0,0 +1,47 @@ +