Test fixtures for PgSQL and MySQL

WIP commit that adds the test fixture code for
MySQL and PgSQL. MonitoringController can be used as the base
class for controller tests and resolves dependencies required
for testing icinga2web controllers. Hopefully we don't need
that much require-foo in the future, as more dependencies should
move into the request class

refs #4417
This commit is contained in:
Jannis Moßhammer 2013-07-16 16:18:02 +02:00
parent 2f79879a2e
commit 0e6de0718e
10 changed files with 3998 additions and 0 deletions

View File

@ -0,0 +1,121 @@
<?php
namespace Icinga\Web
{
class ModuleActionController
{
public $view;
public $params = array();
public function _getParam($param)
{
if (!isset($this->params[$param])) {
return false;
}
return $this->params[$param];
}
public function setBackend($backend)
{
$this->backend = $backend;
}
}
}
namespace Test\Monitoring\Testlib
{
use Test\Monitoring\Testlib\DataSource\TestFixture;
use Test\Monitoring\Testlib\DataSource\DataSourceTestSetup;
use Monitoring\Backend\Ido;
class MonitoringControllerTest extends \PHPUnit_Framework_TestCase
{
private $moduleDir = "";
private $appDir = "";
public function setUp()
{
$this->moduleDir = dirname(__FILE__) . '/../../../';
$this->appDir = $this->moduleDir.'../../library/Icinga/';
$module = $this->moduleDir;
$app = $this->appDir;
set_include_path(get_include_path().':'.$module);
set_include_path(get_include_path().':'.$app);
require_once('Zend/Config.php');
require_once('Zend/Db.php');
require_once(dirname(__FILE__) . '/datasource/DataSourceTestSetup.php');
$this->requireBase();
$this->requireViews();
$this->requireQueries();
}
private function requireBase()
{
require_once('Application/Benchmark.php');
require_once('Data/AbstractQuery.php');
require_once('Data/DatasourceInterface.php');
require_once('Data/Db/Connection.php');
require_once('Data/Db/Query.php');
require_once('Exception/ProgrammingError.php');
require_once('library/Monitoring/Backend/AbstractBackend.php');
require_once('library/Monitoring/Backend/Ido.php');
}
private function requireQueries()
{
$module = $this->moduleDir;
$views = scandir($module.'library/Monitoring/Backend/Ido/Query');
foreach ($views as $view) {
if (!preg_match('/php$/', $view)) {
continue;
}
require_once($module.'library/Monitoring/Backend/Ido/Query/'.$view);
}
}
private function requireViews()
{
$module = $this->moduleDir;
require_once($module.'library/Monitoring/View/MonitoringView.php');
$views = scandir($module.'library/Monitoring/View');
foreach ($views as $view) {
if (!preg_match('/php$/', $view)) {
continue;
}
require_once($module.'library/Monitoring/View/'.$view);
}
}
public function requireController($controller, $backend)
{
require_once($this->moduleDir.'/application/controllers/'.$controller.'.php');
$controllerName = '\Monitoring_'.ucfirst($controller);
$controller = new $controllerName;
$controller->setBackend($this->getBackendFor($backend));
return $controller;
}
public function setupFixture(TestFixture $fixture, $type)
{
$dbInstance = new DataSourceTestSetup($type);
$dbInstance->setup();
$dbInstance->insert($fixture);
}
public function getBackendFor($type) {
if ($type == "mysql" || $type == "pgsql") {
return new Ido(new \Zend_Config(array(
"dbtype"=> $type,
'host' => "localhost",
'user' => "icinga_unittest",
'pass' => "icinga_unittest",
'db' => "icinga_unittest"
)));
}
}
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Test\Monitoring\Testlib\DataSource;
require_once(dirname(__FILE__).'/strategies/InsertionStrategy.php');
require_once(dirname(__FILE__).'/strategies/SetupStrategy.php');
require_once(dirname(__FILE__).'/strategies/MySQLSetupStrategy.php');
require_once(dirname(__FILE__).'/strategies/PgSQLSetupStrategy.php');
require_once(dirname(__FILE__).'/strategies/PDOInsertionStrategy.php');
require_once(dirname(__FILE__).'/TestFixture.php');
use \Test\Monitoring\Testlib\Datasource\Strategies\InsertionStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\SetupStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\MySQLSetupStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\PgSQLSetupStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\PDOInsertionStrategy;
class DataSourceTestSetup implements SetupStrategy, InsertionStrategy
{
private $setupStrategy;
private $insertionStrategy;
public function __construct($type)
{
if ($type == 'mysql') {
$this->setupStrategy = new MySQLSetupStrategy();
$this->insertionStrategy = new PDOInsertionStrategy();
} elseif ($type == 'pgsql') {
$this->setupStrategy = new PgSQLSetupStrategy();
$this->insertionStrategy = new PDOInsertionStrategy();
} else {
throw new \Exception('Unsupported backend '.$type);
}
}
public function insert(TestFixture $fixture) {
$this->insertionStrategy->insert($fixture);
}
public function setup($version = null, $connection = null)
{
$c = $this->setupStrategy->setup($version, $connection);
$this->insertionStrategy->setConnection($c);
}
public function teardown($connection = null)
{
$this->setupStrategy->teardown($connection);
}
public function setConnection($connection)
{
$this->insertionStrategy->setConnection($connection);
}
}

View File

@ -0,0 +1,245 @@
<?php
namespace Test\Monitoring\Testlib\DataSource;
class ObjectFlags {
public $flapping = 0;
public $notifications = 1;
public $active_checks = 1;
public $passive_checks = 1;
public $acknowledged = 0;
public $in_downtime = 0;
public $time = 0;
public function ObjectFlags($ageInSeconds = null) {
if(!is_int($ageInSeconds))
$ageInSeconds = 0;
$this->time = time()-$ageInSeconds;
}
public static function FLAPPING() {
$flags = new ObjectFlags();
$flags->flapping = 0;
return $flags;
}
public static function DISABLE_NOTIFICATIONS() {
$flags = new ObjectFlags();
$flags->notifications = 0;
return $flags;
}
public static function PASSIVE_ONLY() {
$flags = new ObjectFlags();
$flags->active_checks = 0;
return $flags;
}
public static function ACTIVE_ONLY() {
$flags = new ObjectFlags();
$flags->passive_checks = 0;
return $flags;
}
public static function DISABLED() {
$flags = new ObjectFlags();
$flags->passive_checks = 0;
$flags->active_checks = 0;
return $flags;
}
public static function ACKNOWLEDGED() {
$flags = new ObjectFlags();
$flags->acknowledged = 1;
return $flags;
}
public static function IN_DOWNTIME() {
$flags = new ObjectFlags();
$flags->in_downtime = 1;
return $flags;
}
}
class TestFixtureObjectClosure
{
private $scope;
private $environment;
public function __construct(TestFixture $environment, $scope)
{
$this->scope = $scope;
$this->environment = $environment;
}
public function __call($string, $arguments)
{
$callArg = array($this->scope);
$args = array_merge($callArg, $arguments);
return call_user_func_array(array($this->environment, $string), $args);
}
}
class TestFixture
{
private $hosts = array();
private $services = array();
private $contacts = array();
private $comments = array();
private $servicegroups = array();
private $hostgroups = array();
public function getHosts()
{
return $this->hosts;
}
public function getServices()
{
return $this->services;
}
public function getContacts()
{
return $this->contacts;
}
public function getServicegroups()
{
return $this->servicegroups;
}
public function getHostgroups()
{
return $this->hostgroups;
}
public function getComments()
{
return $this->comments;
}
public function addHost($name, $state, ObjectFlags $flags = null, array $additional = array()) {
if ($flags === null) {
$flags = new ObjectFlags();
}
if (isset($this->hosts[$name])) {
throw new Exception('Tried to create hosts twice');
}
$this->hosts[$name] = array(
'name' => $name,
'state' => $state,
'address' => '127.0.0.1',
'flags' => $flags,
'icon_image' => 'icon.png',
'notes_url' => '',
'action_url' => '',
'contacts' => array(),
'customvariables' => array()
);
$this->hosts[$name] = array_merge($this->hosts[$name], $additional);
return new TestFixtureObjectClosure($this, $name);
}
public function addService($host, $name, $state, ObjectFlags $flags = null, array $additional = array()) {
// when called in service scope only use the host
if (is_array($host)) {
$host = $host[0];
}
if ($flags === null) {
$flags = new ObjectFlags();
}
if (!isset($this->hosts[$host])) {
throw new Exception('Tried to create service for non existing host '.$host);
}
if (isset($this->services[$name])) {
throw new Exception('Tried to create service twice '.$name);
}
$this->services[$host.';'.$name] = array(
'host' => &$this->hosts[$host],
'name' => $name,
'state' => $state,
'contacts' => array(),
'icon_image' => 'icon.png',
'notes_url' => '',
'action_url' => '',
'customvariables' => array(),
'flags' => $flags
);
$this->services[$host.';'.$name] = array_merge($this->services[$host.';'.$name], $additional);
return new TestFixtureObjectClosure($this, array($host, $name));
}
public function addComment($hostOrServiceHostPair, $author, $text) {
if (is_array($hostOrServiceHostPair)) {
if (!isset($this->services[$hostOrServiceHostPair[0].';'.$hostOrServiceHostPair[1]])) {
throw new Exception('Tried to add a comment for a nonexisting service '.$hostOrServiceHostPair[1]);
}
$this->comments[] = array(
'service' => &$this->services[$hostOrServiceHostPair[0].';'.$hostOrServiceHostPair[1]],
'author' => $author,
'text' => $text
);
} else {
if (!isset($this->hosts[$hostOrServiceHostPair])) {
throw new Exception('Tried to add a comment for a nonexisting host '.$hostOrServiceHostPair);
}
$this->comments[] = array(
'host' => &$this->hosts[$hostOrServiceHostPair],
'author' => $author,
'text' => $text
);
}
return new TestFixtureObjectClosure($this, $hostOrServiceHostPair);
}
public function assignContact($hostOrServiceHostPair, $contactname) {
$this->contacts[$contactname] = array('alias' => $contactname);
if (is_array($hostOrServiceHostPair)) {
if (!isset($this->services[$hostOrServiceHostPair[0].';'.$hostOrServiceHostPair[1]])) {
throw new Exception('Tried to add a comment for a nonexisting service '.$hostOrServiceHostPair[1]);
}
$service = $this->services[$hostOrServiceHostPair[0].';'.$hostOrServiceHostPair[1]];
$service['contacts'][] = &$this->contacts[$contactname];
} else {
if (!isset($this->hosts[$hostOrServiceHostPair])) {
throw new Exception('Tried to add a comment for a nonexisting host '.$hostOrServiceHostPair);
}
$host = $this->hosts[$hostOrServiceHostPair];
$host['contacts'][] = &$this->contacts[$contactname];
}
return new TestFixtureObjectClosure($this, $hostOrServiceHostPair);
}
public function addToHostgroup($host, $groupname) {
// check if in service scope
if (is_array($host)) {
$host = $host[0];
}
if (!isset($this->hosts[$host])) {
throw new Exception('Tried to add non-existing host '.$host.' to hostgroup ');
}
if (!isset($this->hostgroups[$groupname])) {
$this->hostgroups[$groupname] = array("name" => $groupname, "members" => array());
}
$this->hostgroups[$groupname]["members"][] = &$this->hosts[$host];
return new TestFixtureObjectClosure($this, $host);
}
public function addToServicegroup(array $serviceHostPair, $groupname) {
if (!isset($this->services[$serviceHostPair[0].";".$serviceHostPair[1]])) {
throw new Exception('Tried to add non-existing service '.$serviceHostPair[1].' to servicegroup ');
}
$service = &$this->services[$serviceHostPair[0].";".$serviceHostPair[1]];
if (!isset($this->servicegroups[$groupname])) {
$this->servicegroups[$groupname] = array("name" => $groupname, "members" => array());
}
$this->servicegroups[$groupname]["members"][] = &$service;
return new TestFixtureObjectClosure($this, $serviceHostPair);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
<?php
namespace Test\Monitoring\Testlib\Datasource\Strategies;
use \Test\Monitoring\Testlib\DataSource\TestFixture;
interface InsertionStrategy {
public function setConnection($connection);
public function insert(TestFixture $fixture);
}

View File

@ -0,0 +1,44 @@
<?php
namespace Test\Monitoring\Testlib\Datasource\Strategies;
class MySQLSetupStrategy implements SetupStrategy {
public function setup($version = null, $connection = null)
{
if ($connection === null) {
$connection = new \PDO("mysql:dbname=icinga_unittest", "icinga_unittest", "icinga_unittest");
}
$connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->teardown($connection);
// the latest schema doesn't have a suffix, so if no version is given this one is used
$sqlFileName = 'idoMySQL'.($version !== null ? '-'.$version : '' ).'.sql';
$path = realpath(dirname(__FILE__).'/../schemes/'.$sqlFileName);
if (!file_exists($path)) {
throw new \Exception('File '.$path.' not found: Could not create scheme for IDO mysql backend '.($version ? '(version : '.$version.')' :''));
}
$connection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
if ($connection->query(file_get_contents($path)) === false) {
$error = $connection->errorInfo();;
throw new \PDOException($error[0].' : '.$error[2]);
}
return $connection;
}
public function teardown($connection = null)
{
if ($connection === null) {
$connection = new \PDO("mysql:dbname=icinga_unittest", "icinga_unittest", "icinga_unittest");
}
echo "teardown";
$tables = $connection->query("SHOW TABLES")->fetchAll();
foreach($tables as $table) {
$connection->query("DROP TABLE ".$table[0]);
}
}
}

View File

@ -0,0 +1,212 @@
<?php
namespace Test\Monitoring\Testlib\Datasource\Strategies;
use \Test\Monitoring\Testlib\DataSource\TestFixture;
class PDOInsertionStrategy {
private $objectId = 0;
private $fixture;
private $connection;
public function setConnection($connection) {
$this->connection = $connection;
}
public function insert(TestFixture $fixture)
{
$this->fixture = $fixture;
$this->insertContacts();
$this->insertHosts();
$this->insertServices();
$this->insertComments();
$this->insertHostgroups();
$this->insertServicegroups();
}
private function insertHosts()
{
$hosts = &$this->fixture->getHosts();
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1, is_active) VALUES (?, 1, ?, 1);'
);
$insertHostQuery = $this->connection->prepare(
'INSERT INTO icinga_hosts ('.
'host_id, alias, display_name, address, host_object_id, '.
'icon_image, notes_url, action_url'.
') VALUES (?, ?, ?, ?, ?, ?, ?, ?);'
);
$insertContactQuery = $this->connection->prepare(
'INSERT INTO icinga_host_contacts (host_id, contact_object_id) VALUES (?, ?);'
);
$insertHostStatusQuery = $this->connection->prepare(
'INSERT INTO icinga_hoststatus'.
'(host_object_id, current_state, last_check, notifications_enabled, '.
'active_checks_enabled, passive_checks_enabled, is_flapping, scheduled_downtime_depth)'.
' VALUES (?, ?, ?, ?, ?, ?, ?, ?)'
);
$insertCVQuery = $this->connection->prepare(
'INSERT INTO icinga_customvariablestatus'.
'(object_id, varname, varvalue) VALUES (?, ?, ?)'
);
foreach($hosts as &$host) {
$flags = $host["flags"];
$insertObjectQuery->execute(array($this->objectId, $host["name"]));
$insertHostQuery->execute(array(
$this->objectId, $host["name"], $host["name"], $host["address"], $this->objectId,
$host["icon_image"], $host["notes_url"], $host["action_url"]
));
$insertHostStatusQuery->execute(array(
$this->objectId, $host["state"], $flags->time, $flags->notifications,
$flags->active_checks, $flags->passive_checks, $flags->flapping, $flags->in_downtime));
foreach($host["contacts"] as $contact) {
$insertContactQuery->execute(array($this->objectId, $contact["object_id"]));
}
foreach($host["customvariables"] as $cvName=>$cvValue) {
$insertCVQuery->execute(array($this->objectId, $cvName, $cvValue));
}
$host["object_id"] = $this->objectId;
$this->objectId++;
}
}
private function insertServices()
{
$services = $this->fixture->getServices();
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1, name2, is_active) VALUES (?, 2, ?, ?, 1);'
);
$insertServiceQuery = $this->connection->prepare(
'INSERT INTO icinga_services ('.
'service_id, host_object_id, service_object_id, display_name, '.
'icon_image, notes_url, action_url'.
') VALUES (?, ?, ?, ?, ?, ?, ?)'
);
$insertServiceStatusQuery = $this->connection->prepare(
'INSERT INTO icinga_servicestatus'.
'(service_object_id, current_state, last_check, notifications_enabled, '.
'active_checks_enabled, passive_checks_enabled, is_flapping, scheduled_downtime_depth)'.
' VALUES (?, ?, ?, ?, ?, ?, ?, ?)'
);
$insertContactQuery = $this->connection->prepare(
'INSERT INTO icinga_service_contacts (host_id, contact_object_id) VALUES (?, ?);'
);
$insertCVQuery = $this->connection->prepare(
'INSERT INTO icinga_customvariablestatus'.
'(object_id, varname, varvalue) VALUES (?, ?, ?)'
);
foreach($services as &$service) {
$flags = $service["flags"];
$insertObjectQuery->execute(array($this->objectId, $service["host"]["name"], $service["name"]));
$insertServiceQuery->execute(array(
$this->objectId, $service['host']['object_id'], $this->objectId, $service['name'],
$service["notes_url"], $service["action_url"], $service["icon_image"]
));
$insertServiceStatusQuery->execute(array(
$this->objectId, $service["state"], $flags->time, $flags->notifications,
$flags->active_checks, $flags->passive_checks, $flags->flapping, $flags->in_downtime));
foreach($service["contacts"] as $contact) {
$insertContactQuery->execute(array($this->objectId, $contact["object_id"]));
}
foreach($service["customvariables"] as $cvName=>$cvValue) {
$insertCVQuery->execute(array($this->objectId, $cvName, $cvValue));
}
$service["object_id"] = $this->objectId;
$this->objectId++;
}
}
private function insertContacts()
{
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1) VALUES (?, 10, ?);'
);
$insertContactQuery = $this->connection->prepare(
'INSERT INTO icinga_contacts (contact_object_id, alias) VALUES (?, ?);'
);
$contacts = &$this->fixture->getContacts();
foreach($contacts as &$contact) {
$insertObjectQuery->execute($this->objectId, $contact["alias"]);
$insertContactQuery->execute($this->objectId, $contact["alias"]);
$contact["object_id"] = $this->objectId;
$this->objectId++;
}
}
private function insertComments()
{
$insertCommentsQuery = $this->connection->prepare(
'INSERT INTO icinga_comments (object_id, comment_type, author_name, comment_data) VALUES (?, ?, ?, ?);'
);
$comments = &$this->fixture->getComments();
foreach ($comments as $comment) {
if (isset($comment["host"])) {
$type = 1;
$object_id = $comment["host"]["object_id"];
} elseif (isset($comment["service"])) {
$type = 2;
$object_id = $comment["service"]["object_id"];
}
$insertCommentsQuery->execute(array($object_id, $type, $comment["author"], $comment["text"]));
}
}
private function insertHostgroups()
{
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1) VALUES (?, 3, ?)'
);
$insertHostgroupQuery = $this->connection->prepare(
'INSERT INTO icinga_hostgroups (hostgroup_id, hostgroup_object_id, alias) VALUES (?, ?, ?)'
);
$insertHostgroupMemberQuery = $this->connection->prepare(
'INSERT INTO icinga_hostgroup_members (hostgroup_id, host_object_id) VALUES (?, ?)'
);
$hostgroups = &$this->fixture->getHostgroups();
foreach ($hostgroups as &$hostgroup) {
$insertObjectQuery->execute(array($this->objectId, $hostgroup["name"]));
$insertHostgroupQuery->execute(array($this->objectId, $this->objectId, $hostgroup["name"]));
foreach ($hostgroup["members"] as $member) {
$insertHostgroupMemberQuery->execute(array($this->objectId, $member["object_id"]));
}
$this->objectId++;
}
}
private function insertServicegroups()
{
$insertObjectQuery = $this->connection->prepare(
'INSERT INTO icinga_objects (object_id, objecttype_id, name1) VALUES (?, 4, ?)'
);
$insertServicegroupQuery = $this->connection->prepare(
'INSERT INTO icinga_servicegroups (servicegroup_id, servicegroup_object_id, alias) VALUES (?, ?, ?)'
);
$insertServicegroupMemberQuery = $this->connection->prepare(
'INSERT INTO icinga_servicegroup_members (servicegroup_id, service_object_id) VALUES (?, ?)'
);
$servicegroups = &$this->fixture->getServicegroups();
foreach ($servicegroups as &$servicegroup) {
$insertObjectQuery->execute(array($this->objectId, $servicegroup["name"]));
$insertServicegroupQuery->execute(array($this->objectId, $this->objectId, $servicegroup["name"]));
foreach ($servicegroup["members"] as $member) {
$insertServicegroupMemberQuery->execute(array($this->objectId, $member["object_id"]));
}
$this->objectId++;
}
}
}

View File

@ -0,0 +1,52 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: moja
* Date: 7/16/13
* Time: 3:30 PM
* To change this template use File | Settings | File Templates.
*/
namespace Test\Monitoring\Testlib\Datasource\Strategies;
class PgSQLSetupStrategy {
public function setup($version = null, $connection = null)
{
if ($connection === null) {
$connection = new \PDO('pgsql:dbname=icinga_unittest', 'icinga_unittest', 'icinga_unittest');
}
$connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->teardown($connection);
// the latest schema doesn't have a suffix, so if no version is given this one is used
$sqlFileName = 'idoPgSQL'.($version !== null ? '-'.$version : '' ).'.sql';
$path = realpath(dirname(__FILE__).'/../schemes/'.$sqlFileName);
if (!file_exists($path)) {
throw new \Exception('File '.$path.' not found: Could not create scheme for IDO pgsql backend '.($version ? '(version : '.$version.')' :''));
}
$connection->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
if ($connection->query(file_get_contents($path)) === false) {
$error = $connection->errorInfo();;
throw new \PDOException($error[0].' : '.$error[2]);
}
return $connection;
}
public function teardown($connection = null)
{
if ($connection === null) {
$connection = new \PDO('pgsql:dbname=icinga_unittest', 'icinga_unittest', 'icinga_unittest');
}
$tables = $connection
->query('SELECT table_schema,table_name FROM information_schema.tables WHERE table_type = \'BASE TABLE\''.
'AND table_schema = \'public\' ORDER BY table_schema,table_name;')
->fetchAll();
foreach($tables as $table) {
$connection->query('DROP TABLE '.$table['table_name']);
}
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace Test\Monitoring\Testlib\Datasource\Strategies;
interface SetupStrategy {
public function setup($version = null, $connection = null);
public function teardown($connection = null);
}