diff options
Diffstat (limited to 'library/Director/Test')
-rw-r--r-- | library/Director/Test/BaseTestCase.php | 127 | ||||
-rw-r--r-- | library/Director/Test/Bootstrap.php | 28 | ||||
-rw-r--r-- | library/Director/Test/IcingaObjectTestCase.php | 92 | ||||
-rw-r--r-- | library/Director/Test/ImportSourceDummy.php | 52 | ||||
-rw-r--r-- | library/Director/Test/SyncTest.php | 105 | ||||
-rw-r--r-- | library/Director/Test/TestProcess.php | 116 | ||||
-rw-r--r-- | library/Director/Test/TestSuite.php | 68 | ||||
-rw-r--r-- | library/Director/Test/TestSuiteLint.php | 56 | ||||
-rw-r--r-- | library/Director/Test/TestSuiteStyle.php | 66 | ||||
-rw-r--r-- | library/Director/Test/TestSuiteUnit.php | 26 | ||||
-rw-r--r-- | library/Director/Test/Web/Form/TestDirectorObjectForm.php | 19 |
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; + } +} |