summaryrefslogtreecommitdiffstats
path: root/library/Director/Test
diff options
context:
space:
mode:
Diffstat (limited to 'library/Director/Test')
-rw-r--r--library/Director/Test/BaseTestCase.php127
-rw-r--r--library/Director/Test/Bootstrap.php28
-rw-r--r--library/Director/Test/IcingaObjectTestCase.php92
-rw-r--r--library/Director/Test/ImportSourceDummy.php52
-rw-r--r--library/Director/Test/SyncTest.php105
-rw-r--r--library/Director/Test/TestProcess.php116
-rw-r--r--library/Director/Test/TestSuite.php68
-rw-r--r--library/Director/Test/TestSuiteLint.php56
-rw-r--r--library/Director/Test/TestSuiteStyle.php66
-rw-r--r--library/Director/Test/TestSuiteUnit.php26
-rw-r--r--library/Director/Test/Web/Form/TestDirectorObjectForm.php19
11 files changed, 755 insertions, 0 deletions
diff --git a/library/Director/Test/BaseTestCase.php b/library/Director/Test/BaseTestCase.php
new file mode 100644
index 0000000..611805b
--- /dev/null
+++ b/library/Director/Test/BaseTestCase.php
@@ -0,0 +1,127 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+use Icinga\Application\Icinga;
+use Icinga\Application\Config;
+use Icinga\Data\ResourceFactory;
+use Icinga\Exception\ConfigurationError;
+use Icinga\Module\Director\Db;
+use Icinga\Module\Director\Db\Migrations;
+use Icinga\Module\Director\Objects\IcingaObject;
+use Icinga\Module\Director\Objects\IcingaZone;
+use PHPUnit_Framework_TestCase;
+
+abstract class BaseTestCase extends PHPUnit_Framework_TestCase
+{
+ private static $app;
+
+ /** @var Db */
+ private static $db;
+
+ public function setUp()
+ {
+ $this->app();
+ }
+
+ protected function skipForMissingDb()
+ {
+ if ($this->hasDb()) {
+ return false;
+ }
+
+ $this->markTestSkipped('Test db resource has not been configured');
+
+ return true;
+ }
+
+ protected function hasDb()
+ {
+ return $this->getDbResourceName() !== null;
+ }
+
+ protected static function getDbResourceName()
+ {
+ if (array_key_exists('DIRECTOR_TESTDB_RES', $_SERVER)) {
+ return $_SERVER['DIRECTOR_TESTDB_RES'];
+ } else {
+ return Config::module('director')->get('testing', 'db_resource');
+ }
+ }
+
+ /**
+ * @return Db
+ * @throws ConfigurationError
+ */
+ protected static function getDb()
+ {
+ if (self::$db === null) {
+ $resourceName = self::getDbResourceName();
+ if (! $resourceName) {
+ throw new ConfigurationError(
+ 'Could not run DB-based tests, please configure a testing db resource'
+ );
+ }
+ $dbConfig = ResourceFactory::getResourceConfig($resourceName);
+ if (array_key_exists('DIRECTOR_TESTDB', $_SERVER)) {
+ $dbConfig->dbname = $_SERVER['DIRECTOR_TESTDB'];
+ }
+ if (array_key_exists('DIRECTOR_TESTDB_HOST', $_SERVER)) {
+ $dbConfig->host = $_SERVER['DIRECTOR_TESTDB_HOST'];
+ }
+ if (array_key_exists('DIRECTOR_TESTDB_USER', $_SERVER)) {
+ $dbConfig->username = $_SERVER['DIRECTOR_TESTDB_USER'];
+ }
+ if (array_key_exists('DIRECTOR_TESTDB_PASSWORD', $_SERVER)) {
+ $dbConfig->password = $_SERVER['DIRECTOR_TESTDB_PASSWORD'];
+ }
+ self::$db = new Db($dbConfig);
+ $migrations = new Migrations(self::$db);
+ $migrations->applyPendingMigrations();
+ IcingaZone::create([
+ 'object_name' => 'director-global',
+ 'object_type' => 'external_object',
+ 'is_global' => 'y'
+ ])->store(self::$db);
+ }
+
+ return self::$db;
+ }
+
+ protected function newObject($type, $name, $properties = array())
+ {
+ if (! array_key_exists('object_type', $properties)) {
+ $properties['object_type'] = 'object';
+ }
+ $properties['object_name'] = $name;
+
+ return IcingaObject::createByType($type, $properties, $this->getDb());
+ }
+
+ protected function app()
+ {
+ if (self::$app === null) {
+ self::$app = Icinga::app();
+ }
+
+ return self::$app;
+ }
+
+ /**
+ * Call a protected function for a class during testing
+ *
+ * @param $obj
+ * @param $name
+ * @param array $args
+ *
+ * @return mixed
+ * @throws \ReflectionException
+ */
+ public static function callMethod($obj, $name, array $args)
+ {
+ $class = new \ReflectionClass($obj);
+ $method = $class->getMethod($name);
+ $method->setAccessible(true);
+ return $method->invokeArgs($obj, $args);
+ }
+}
diff --git a/library/Director/Test/Bootstrap.php b/library/Director/Test/Bootstrap.php
new file mode 100644
index 0000000..56bd85a
--- /dev/null
+++ b/library/Director/Test/Bootstrap.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+use Icinga\Application\Cli;
+
+class Bootstrap
+{
+ public static function cli($basedir = null)
+ {
+ error_reporting(E_ALL | E_STRICT);
+ if ($basedir === null) {
+ $basedir = dirname(dirname(dirname(__DIR__)));
+ }
+ $testsDir = $basedir . '/test';
+ require_once 'Icinga/Application/Cli.php';
+
+ if (array_key_exists('ICINGAWEB_CONFIGDIR', $_SERVER)) {
+ $configDir = $_SERVER['ICINGAWEB_CONFIGDIR'];
+ } else {
+ $configDir = $testsDir . '/config';
+ }
+
+ Cli::start($testsDir, $configDir)
+ ->getModuleManager()
+ ->loadModule('director', $basedir);
+ }
+}
diff --git a/library/Director/Test/IcingaObjectTestCase.php b/library/Director/Test/IcingaObjectTestCase.php
new file mode 100644
index 0000000..a37fced
--- /dev/null
+++ b/library/Director/Test/IcingaObjectTestCase.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+use Icinga\Module\Director\Objects\IcingaObject;
+
+/**
+ * Icinga Object test helper class
+ */
+abstract class IcingaObjectTestCase extends BaseTestCase
+{
+ protected $table;
+ protected $testObjectName = '___TEST___';
+
+ /** @var IcingaObject */
+ protected $subject = null;
+
+ protected $createdObjects = array();
+
+ /**
+ * Creates a fresh object to play with and prepares for tearDown()
+ *
+ * @param string $type table to load from
+ * @param string $object_name of the object
+ * @param array $properties
+ * @param bool $storeIt
+ *
+ * @return IcingaObject
+ */
+ protected function createObject($object_name, $type = null, $properties = array(), $storeIt = true)
+ {
+ if ($type === null) {
+ $type = $this->table;
+ }
+ $properties['object_name'] = '___TEST___' . $type . '_' . $object_name;
+ $obj = IcingaObject::createByType($type, $properties, $this->getDb());
+
+ if ($storeIt === true) {
+ $obj->store();
+ $this->prepareObjectTearDown($obj);
+ }
+
+ return $obj;
+ }
+
+ /**
+ * Helper method for loading an object
+ *
+ * @param string $name
+ * @param null $type
+ * @return IcingaObject
+ */
+ protected function loadObject($name, $type = null)
+ {
+ if ($type === null) {
+ $type = $this->table;
+ }
+ $realName = '___TEST___' . $type . '_' . $name;
+ return IcingaObject::loadByType($type, $realName, $this->getDb());
+ }
+
+ /**
+ * Store the object in a list for deletion on tearDown()
+ *
+ * @param IcingaObject $object
+ *
+ * @return $this
+ */
+ protected function prepareObjectTearDown(IcingaObject $object)
+ {
+ $this->assertTrue($object->hasBeenLoadedFromDb());
+ $this->createdObjects[] = $object;
+ return $this;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function tearDown()
+ {
+ if ($this->hasDb()) {
+ /** @var IcingaObject $object */
+ foreach (array_reverse($this->createdObjects) as $object) {
+ $object->delete();
+ }
+
+ if ($this->subject !== null) {
+ $this->subject->delete();
+ }
+ }
+ }
+}
diff --git a/library/Director/Test/ImportSourceDummy.php b/library/Director/Test/ImportSourceDummy.php
new file mode 100644
index 0000000..4ac1d09
--- /dev/null
+++ b/library/Director/Test/ImportSourceDummy.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+use Icinga\Module\Director\Hook\ImportSourceHook;
+
+class ImportSourceDummy extends ImportSourceHook
+{
+ protected static $rows = array();
+
+ /**
+ * Returns an array containing importable objects
+ *
+ * @return array
+ */
+ public function fetchData()
+ {
+ return self::$rows;
+ }
+
+ /**
+ * Returns a list of all available columns
+ *
+ * @return array
+ */
+ public function listColumns()
+ {
+ $keys = array();
+ foreach (self::$rows as $row) {
+ $keys = array_merge($keys, array_keys($row));
+ }
+ return $keys;
+ }
+
+ public static function clearRows()
+ {
+ self::$rows = array();
+ }
+
+ public static function setRows($rows)
+ {
+ static::clearRows();
+ foreach ($rows as $row) {
+ static::addRow($row);
+ }
+ }
+
+ public static function addRow($row)
+ {
+ self::$rows[] = (object) $row;
+ }
+}
diff --git a/library/Director/Test/SyncTest.php b/library/Director/Test/SyncTest.php
new file mode 100644
index 0000000..7614ff9
--- /dev/null
+++ b/library/Director/Test/SyncTest.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+use Icinga\Exception\IcingaException;
+use Icinga\Module\Director\Data\Db\DbObject;
+use Icinga\Module\Director\Db\Cache\PrefetchCache;
+use Icinga\Module\Director\Import\Sync;
+use Icinga\Module\Director\Objects\IcingaObject;
+use Icinga\Module\Director\Objects\ImportSource;
+use Icinga\Module\Director\Objects\SyncProperty;
+use Icinga\Module\Director\Objects\SyncRule;
+
+abstract class SyncTest extends BaseTestCase
+{
+ protected $objectType;
+
+ protected $keyColumn;
+
+ /** @var ImportSource */
+ protected $source;
+
+ /** @var SyncRule */
+ protected $rule;
+
+ /** @var SyncProperty[] */
+ protected $properties = array();
+
+ /** @var Sync */
+ protected $sync;
+
+ public function setUp()
+ {
+ $this->source = ImportSource::create(array(
+ 'source_name' => 'testimport',
+ 'provider_class' => 'Icinga\\Module\\Director\\Test\\ImportSourceDummy',
+ 'key_column' => $this->keyColumn,
+ ));
+ $this->source->store($this->getDb());
+
+ $this->rule = SyncRule::create(array(
+ 'rule_name' => 'testrule',
+ 'object_type' => $this->objectType,
+ 'update_policy' => 'merge',
+ 'purge_existing' => 'n'
+ ));
+ $this->rule->store($this->getDb());
+
+ $this->sync = new Sync($this->rule);
+ }
+
+ public function tearDown()
+ {
+ // properties should be deleted automatically
+ if ($this->rule !== null && $this->rule->hasBeenLoadedFromDb()) {
+ $this->rule->delete();
+ }
+
+ if ($this->source !== null && $this->source->hasBeenLoadedFromDb()) {
+ $this->source->delete();
+ }
+
+ // find objects created by this class and delete them
+ $db = $this->getDb();
+ $dummy = IcingaObject::createByType($this->objectType, array(), $db);
+ $query = $db->getDbAdapter()->select()
+ ->from($dummy->getTableName())
+ ->where('object_name LIKE ?', 'SYNCTEST_%');
+
+ /** @var IcingaObject $object */
+ foreach (IcingaObject::loadAllByType($this->objectType, $db, $query) as $object) {
+ $object->delete();
+ }
+
+ // make sure cache is clean for other tests
+ PrefetchCache::forget();
+ DbObject::clearAllPrefetchCaches();
+ }
+
+ /**
+ * @param array $rows
+ *
+ * @throws IcingaException
+ */
+ protected function runImport($rows)
+ {
+ ImportSourceDummy::setRows($rows);
+ $this->source->runImport();
+ if ($this->source->get('import_state') !== 'in-sync') {
+ throw new IcingaException('Import failed: %s', $this->source->get('last_error_message'));
+ }
+ }
+
+ protected function setUpProperty($properties = array())
+ {
+ $properties = array_merge(array(
+ 'rule_id' => $this->rule->id,
+ 'source_id' => $this->source->id,
+ 'merge_policy' => 'override',
+ ), $properties);
+
+ $this->properties[] = $property = SyncProperty::create($properties);
+ $property->store($this->getDb());
+ }
+}
diff --git a/library/Director/Test/TestProcess.php b/library/Director/Test/TestProcess.php
new file mode 100644
index 0000000..b2399b7
--- /dev/null
+++ b/library/Director/Test/TestProcess.php
@@ -0,0 +1,116 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+use Closure;
+
+class TestProcess
+{
+ protected $command;
+
+ protected $identifier;
+
+ protected $exitCode;
+
+ protected $output;
+
+ protected $onSuccess;
+
+ protected $onFailure;
+
+ protected $expectedExitCode = 0;
+
+ public function __construct($command, $identifier = null)
+ {
+ $this->command = $command;
+ $this->identifier = $identifier;
+ }
+
+ public function getIdentifier()
+ {
+ return $this->identifier;
+ }
+
+ public function expectExitCode($code)
+ {
+ $this->expectedExitCode = $code;
+ return $this;
+ }
+
+ public function onSuccess($func)
+ {
+ $this->onSuccess = $this->makeClosure($func);
+ return $this;
+ }
+
+ public function onFailure($func)
+ {
+ $this->onSuccess = $this->makeClosure($func);
+ return $this;
+ }
+
+ protected function makeClosure($func)
+ {
+ if ($func instanceof Closure) {
+ return $func;
+ }
+
+ if (is_array($func)) {
+ return function ($process) use ($func) {
+ return $func[0]->{$func[1]}($process);
+ };
+ }
+ }
+
+ public function onFailureThrow($message, $class = 'Exception')
+ {
+ return $this->onFailure(function () use ($message, $class) {
+ throw new $class($message);
+ });
+ }
+
+ public function run()
+ {
+ exec($this->command, $this->output, $this->exitCode);
+
+ if ($this->succeeded()) {
+ $this->triggerSuccess();
+ } else {
+ $this->triggerFailure();
+ }
+ }
+
+ public function succeeded()
+ {
+ return $this->exitCode === $this->expectedExitCode;
+ }
+
+ public function failed()
+ {
+ return $this->exitCode !== $this->expectedExitCode;
+ }
+
+ protected function triggerSuccess()
+ {
+ if (($func = $this->onSuccess) !== null) {
+ $func($this);
+ }
+ }
+
+ protected function triggerFailure()
+ {
+ if (($func = $this->onFailure) !== null) {
+ $func($this);
+ }
+ }
+
+ public function getExitCode()
+ {
+ return $this->exitCode;
+ }
+
+ public function getOutput()
+ {
+ return implode("\n", $this->output) . "\n";
+ }
+}
diff --git a/library/Director/Test/TestSuite.php b/library/Director/Test/TestSuite.php
new file mode 100644
index 0000000..131b974
--- /dev/null
+++ b/library/Director/Test/TestSuite.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+use Icinga\Application\Icinga;
+use RecursiveDirectoryIterator;
+use RecursiveIteratorIterator;
+
+abstract class TestSuite
+{
+ private $basedir;
+
+ abstract public function run();
+
+ public static function newTempfile()
+ {
+ return tempnam(sys_get_temp_dir(), 'DirectorTest-');
+ }
+
+ public function process($command, $identifier = null)
+ {
+ return new TestProcess($command, $identifier);
+ }
+
+ protected function filesByExtension($base, $extensions)
+ {
+ $files = array();
+
+ if (! is_array($extensions)) {
+ $extensions = array($extensions);
+ }
+
+ $basedir = $this->getBaseDir() . '/' . $base;
+ $dir = new RecursiveDirectoryIterator($basedir);
+ $iterator = new RecursiveIteratorIterator(
+ $dir,
+ RecursiveIteratorIterator::SELF_FIRST
+ );
+
+ foreach ($iterator as $file) {
+ if (! $file->isFile()) {
+ continue;
+ }
+
+ if (in_array($file->getExtension(), $extensions)) {
+ $files[] = $file->getPathname();
+ }
+ }
+
+ return $files;
+ }
+
+ public function getBaseDir($file = null)
+ {
+ if ($this->basedir === null) {
+ $this->basedir = Icinga::app()
+ ->getModuleManager()
+ ->getModule('director')
+ ->getBaseDir();
+ }
+
+ if ($file === null) {
+ return $this->basedir;
+ } else {
+ return $this->basedir . '/' . $file;
+ }
+ }
+}
diff --git a/library/Director/Test/TestSuiteLint.php b/library/Director/Test/TestSuiteLint.php
new file mode 100644
index 0000000..41941eb
--- /dev/null
+++ b/library/Director/Test/TestSuiteLint.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+use Icinga\Application\Logger;
+
+class TestSuiteLint extends TestSuite
+{
+ protected $checked;
+
+ protected $failed;
+
+ public function run()
+ {
+ $this->checked = $this->failed = array();
+
+ foreach ($this->listFiles() as $file) {
+ $checked[] = $file;
+ $cmd = "php -l '$file'";
+ $this->result[$file] = $this
+ ->process($cmd, $file)
+ ->onFailure(array($this, 'failedCheck'))
+ ->run();
+ }
+ }
+
+ public function failedCheck($process)
+ {
+ Logger::error($process->getOutput());
+ $this->failed[] = $process->getIdentifier();
+ }
+
+ public function hasFailures()
+ {
+ return ! empty($this->failed);
+ }
+
+ protected function listFiles()
+ {
+ $basedir = $this->getBaseDir();
+ $files = array(
+ $basedir . '/run.php',
+ $basedir . '/configuration.php'
+ );
+
+ foreach ($this->filesByExtension('library/Director', 'php') as $file) {
+ $files[] = $file;
+ }
+
+ foreach ($this->filesByExtension('application', array('php', 'phtml')) as $file) {
+ $files[] = $file;
+ }
+
+ return $files;
+ }
+}
diff --git a/library/Director/Test/TestSuiteStyle.php b/library/Director/Test/TestSuiteStyle.php
new file mode 100644
index 0000000..babd43c
--- /dev/null
+++ b/library/Director/Test/TestSuiteStyle.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+class TestSuiteStyle extends TestSuite
+{
+ public function run()
+ {
+ $out = static::newTempFile();
+ $check = array(
+ 'library/Director/',
+ 'application/',
+ 'configuration.php',
+ 'run.php',
+ );
+
+ /*
+ $options = array();
+ if ($this->isVerbose) {
+ $options[] = '-v';
+ }
+ */
+
+ /*
+ $phpcs = exec('which phpcs');
+ if (!file_exists($phpcs)) {
+ $this->fail(
+ 'PHP_CodeSniffer not found. Please install PHP_CodeSniffer to be able to run code style tests.'
+ );
+ }
+ */
+
+ $cmd = sprintf(
+ "phpcs -p --standard=PSR2 --extensions=php --encoding=utf-8 -w -s --report-checkstyle=%s '%s'",
+ $out,
+ implode("' '", $check)
+ );
+
+ $proc = $this
+ ->process($cmd);
+
+ // ->onFailure(array($this, 'failedCheck'))
+ $proc->run();
+
+ echo $proc->getOutput();
+
+ echo file_get_contents($out);
+ unlink($out);
+ // /usr/bin/phpcs --standard=PSR2 --extensions=php --encoding=utf-8 application/
+ // library/Director/ --report=full
+
+ /*
+ $options[] = '--log-junit';
+ $options[] = $reportPath . '/phpunit_results.xml';
+ $options[] = '--coverage-html';
+ $options[] = $reportPath . '/php_html_coverage';
+ */
+ return;
+
+ `$cmd`;
+ echo $cmd . "\n";
+ echo $out ."\n";
+ echo file_get_contents($out);
+ unlink($out);
+ }
+}
diff --git a/library/Director/Test/TestSuiteUnit.php b/library/Director/Test/TestSuiteUnit.php
new file mode 100644
index 0000000..8156eba
--- /dev/null
+++ b/library/Director/Test/TestSuiteUnit.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Icinga\Module\Director\Test;
+
+abstract class TestSuiteUnit
+{
+ public function run()
+ {
+ }
+ public function __construct()
+ {
+ $this->testdoxFile = $this->newTempfile();
+ }
+
+ public function __destruct()
+ {
+ if ($this->testdoxFile && file_exists($this->testdoxFile)) {
+ unlink($this->testDoxfile);
+ }
+ }
+
+ public function getPhpunitCommand()
+ {
+ // return phpunit --bootstrap test/bootstrap.php --testdox-text /tmp/testdox.txt .
+ }
+}
diff --git a/library/Director/Test/Web/Form/TestDirectorObjectForm.php b/library/Director/Test/Web/Form/TestDirectorObjectForm.php
new file mode 100644
index 0000000..0722e78
--- /dev/null
+++ b/library/Director/Test/Web/Form/TestDirectorObjectForm.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Icinga\Module\Director\Test\Web;
+
+use Icinga\Module\Director\Web\Form\DirectorObjectForm;
+
+class TestDirectorObjectForm extends DirectorObjectForm
+{
+ protected function getActionFromRequest()
+ {
+ $this->setAction('director/test/url');
+ return $this;
+ }
+
+ public function regenerateCsrfToken()
+ {
+ return $this;
+ }
+}