Add documentation for testlib

This commit is contained in:
Jannis Moßhammer 2013-07-18 17:15:32 +02:00
parent 8cc3139f17
commit 281d27255b
12 changed files with 830 additions and 41 deletions

View File

@ -1,12 +1,33 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Web
{
/**
* Mocked controller base class to avoid the complete
* Bootstrap dependency of the normally used ModuleActionController
*/
class ModuleActionController
{
/**
* The view this controller would create
* @var stdClass
*/
public $view;
/**
* Parameters provided on call
* @var array
*/
public $params = array();
/**
* _getParam method that normally retrieves GET/POST parameters
*
* @param string $param The parameter name to retrieve
* @return mixed|bool The parameter $param or false if it doesn't exist
*/
public function _getParam($param)
{
if (!isset($this->params[$param])) {
@ -14,6 +35,12 @@ namespace Icinga\Web
}
return $this->params[$param];
}
/**
* Sets the backend for this controller which will be used in the action
*
* @param $backend
*/
public function setBackend($backend)
{
$this->backend = $backend;
@ -30,10 +57,51 @@ namespace Test\Monitoring\Testlib
use Monitoring\Backend\Ido;
use Monitoring\Backend\Statusdat;
/**
* Base class for monitoring controllers that loads required dependencies
* and allows easier setup of tests
*
* Example:
* <code>
*
* class MyControllerTest extends MonitoringControllerTest
* {
* public function testSomething()
* {
* // Create a test fixture
* $fixture = new TestFixture()
* $fixture->addHost('host', 0)->addService(...)->..->;
*
* $this->setupFixture($fixture, "mysql"); // setup the fixture
* $controller = $this->requireController('MyController', 'mysql');
* // controller is now the Zend controller instance, perform an action
* $controller->myAction();
* $result = $controller->view->hosts->fetchAll();
* // assert stuff
* }
* }
*/
class MonitoringControllerTest extends \PHPUnit_Framework_TestCase
{
/**
* The module directory for requiring modules (is relative to the source file)
* @var string
*/
private $moduleDir = "";
/**
* The application directory for requirying library files (is relative to the source file)
* @var string
*/
private $appDir = "";
/**
* Require necessary libraries on test creation
*
* This is called for every test and assures that all required libraries for the controllers
* are loaded. If you need additional dependencies you should overwrite this method, call the parent
* and then require your classes
*/
public function setUp()
{
$this->moduleDir = dirname(__FILE__) . '/../../../';
@ -51,6 +119,10 @@ namespace Test\Monitoring\Testlib
$this->requireViews();
}
/**
* Require base application and data retrieval classes from the Icinga Library
*
*/
private function requireBase()
{
require_once('Application/Benchmark.php');
@ -64,12 +136,21 @@ namespace Test\Monitoring\Testlib
}
/**
* Require all defined IDO queries in this module
*
*/
private function requireIDOQueries()
{
require_once('library/Monitoring/Backend/Ido.php');
$this->requireFolder('library/Monitoring/Backend/Ido/Query');
}
/**
* Require all php files in the folder $folder
*
* @param $folder The path to the folder containing PHP files
*/
private function requireFolder($folder)
{
$module = $this->moduleDir;
@ -82,6 +163,10 @@ namespace Test\Monitoring\Testlib
}
}
/**
* Require all views and queries from the statusdat backen
*
*/
private function requireStatusDatQueries()
{
require_once('library/Monitoring/Backend/Statusdat.php');
@ -93,6 +178,9 @@ namespace Test\Monitoring\Testlib
$this->requireFolder('library/Monitoring/Backend/Statusdat/DataView');
}
/**
* Require all (generic) view classes from the monitoring module
*/
private function requireViews()
{
$module = $this->moduleDir;
@ -100,6 +188,13 @@ namespace Test\Monitoring\Testlib
$this->requireFolder('library/Monitoring/View/');
}
/**
* Require and set up a controller $controller using the backend type specified at $backend
*
* @param string $controller The name of the controller tu use (must be under monitoring/application/controllers)
* @param string $backend The backend to use ('mysql', 'pgsql' or 'statusdat')
* @return ModuleActionController The newly created controller
*/
public function requireController($controller, $backend)
{
require_once($this->moduleDir.'/application/controllers/'.$controller.'.php');
@ -109,14 +204,25 @@ namespace Test\Monitoring\Testlib
return $controller;
}
/**
* Create a new backend and insert the given fixture into it
*
* @param TestFixture $fixture The TestFixture to create
* @param string $type The type of the backend ('mysql', 'pgsql' or 'statusdat')
*/
public function setupFixture(TestFixture $fixture, $type)
{
$dbInstance = new DataSourceTestSetup($type);
$dbInstance->setup();
$dbInstance->insert($fixture);
}
/**
* Set up and configure a new testbackend for the given type
*
* @param string $type The type of the backend 'mysql', 'pgsql' or 'statusdat'
* @return Ido|Statusdat The newly created backend
*/
public function getBackendFor($type) {
if ($type == "mysql" || $type == "pgsql") {
$this->requireIDOQueries();
@ -134,7 +240,6 @@ namespace Test\Monitoring\Testlib
'objects_file' => '/tmp/testobjects.cache',
'no_cache' => true
)));
}
}
}

View File

@ -1,4 +1,6 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\DataSource;
@ -22,12 +24,48 @@ use \Test\Monitoring\Testlib\Datasource\Strategies\PDOInsertionStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\StatusdatInsertionStrategy;
use \Test\Monitoring\Testlib\Datasource\Strategies\StatusdatSetupStrategy;
/**
* Fascade class that handles creation of test-fixture backends
*
* This class handles the creation and combination of SetupStrategies and InsertionStrategy
* when testing controllers/queries with different backends.
*
* Example:
* <code>
* // TestFixtures contain the objects that should be written for testing
* $fixture = new TestFixture();
* $fixture->addHost(..)->... // setup fixture
*
* $ds = new DataSourceTestSetup('mysql');
* $ds->setup(); // create a blank datasource
* $ds->insert($fixture);
* </code>
*
*
*/
class DataSourceTestSetup implements SetupStrategy, InsertionStrategy
{
/**
* The SetupStrategy that is used on 'setup'
* @var \Test\Monitoring\Testlib\Datasource\Strategies\StatusdatSetupStrategy
*/
private $setupStrategy;
/**
* The InsertionStrategy that is used on 'insert'
* @var \Test\Monitoring\Testlib\Datasource\Strategies\StatusdatInsertionStrategy
*/
private $insertionStrategy;
/**
* Create a DataSource for the backend $type.
*
* On creation, a suitable setup/insert combination will be used
* for the provided backend, so the caller needn't to care about which
* setup or insertion strategy he wants to use.
*
* @param String $type The type of the backend (currently 'mysql', 'pgsql' and 'statusdat')
*/
public function __construct($type)
{
if ($type == 'mysql') {
@ -45,13 +83,23 @@ class DataSourceTestSetup implements SetupStrategy, InsertionStrategy
} else {
throw new \Exception('Unsupported backend '.$type);
}
}
/**
* Insert a testfixture into this datasource
*
* @param TestFixture $fixture The fixture to insert into the datasource
*/
public function insert(TestFixture $fixture) {
$this->insertionStrategy->insert($fixture);
}
/**
* Create a blank datasource that can be filled with TestFixtures afterwards
*
* @param String $version An (optional) version to use for creation
* @param mixed $connection An (optional) connection to use for this datasource
*/
public function setup($version = null, $connection = null)
{
$c = $this->setupStrategy->setup($version, $connection);
@ -59,14 +107,24 @@ class DataSourceTestSetup implements SetupStrategy, InsertionStrategy
$this->insertionStrategy->setConnection($c);
}
/**
* Remove all testdata created in this datasource
*
* @param mixed $connection An optional connection to use for clean up
*/
public function teardown($connection = null)
{
$this->setupStrategy->teardown($connection);
}
/**
* Sets the connection to use for writing to this datasource
*
* @param mixed $connection The connection to use. The actual type depends
* on the used backend
*/
public function setConnection($connection)
{
$this->insertionStrategy->setConnection($connection);
}
}

View File

@ -1,16 +1,67 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\DataSource;
/**
* Status flags for objects
*
*/
class ObjectFlags {
/**
* 1 if the test host is flapping, otherwise 0
* @var int
*/
public $flapping = 0;
/**
* 1 if the test host has notifications enabled, otherwise 0
* @var int
*/
public $notifications = 1;
/**
* 1 if the test host is active, otherwise 0
* @var int
*/
public $active_checks = 1;
/**
* 1 if the test host allows passive checks, otherwise 0
* @var int
*/
public $passive_checks = 1;
/**
* 1 if the test host is acknowledged, otherwise 0
* @var int
*/
public $acknowledged = 0;
/**
* 1 if the test host is in a downtime, otherwise 0
* @var int
*/
public $in_downtime = 0;
/**
* 1 if the test host is pending, otherwise 0
* @var int
*/
public $is_pending = 0;
/**
* The last check and state change time as a UNIX timestamp
* @var int
*/
public $time = 0;
/**
* Create a new ObjectFlags instance with default values
*
* @param int $ageInSeconds How old this check should be in seconds
*/
public function __construct($ageInSeconds = null)
{
if(!is_int($ageInSeconds))
@ -18,6 +69,11 @@ class ObjectFlags {
$this->time = time()-$ageInSeconds;
}
/**
* Create a new ObjectFlags object that is in 'flapping' state
*
* @return ObjectFlags
*/
public static function FLAPPING()
{
$flags = new ObjectFlags();
@ -25,6 +81,11 @@ class ObjectFlags {
return $flags;
}
/**
* Create a new ObjectFlags object that is in 'pending' state
*
* @return ObjectFlags
*/
public static function PENDING()
{
$flags = new ObjectFlags();
@ -32,6 +93,11 @@ class ObjectFlags {
return $flags;
}
/**
* Create a new ObjectFlags object that is in 'notifications_disabled' state
*
* @return ObjectFlags
*/
public static function DISABLE_NOTIFICATIONS()
{
$flags = new ObjectFlags();
@ -39,6 +105,11 @@ class ObjectFlags {
return $flags;
}
/**
* Create a new ObjectFlags object that has active checks disabled but passive enabled
*
* @return ObjectFlags
*/
public static function PASSIVE_ONLY()
{
$flags = new ObjectFlags();
@ -46,6 +117,11 @@ class ObjectFlags {
return $flags;
}
/**
* Create a new ObjectFlags object that has passive checks disabled but active enabled
*
* @return ObjectFlags
*/
public static function ACTIVE_ONLY()
{
$flags = new ObjectFlags();
@ -53,7 +129,11 @@ class ObjectFlags {
return $flags;
}
/**
* Create a new ObjectFlags object that is neither active nor passive
*
* @return ObjectFlags
*/
public static function DISABLED() {
$flags = new ObjectFlags();
$flags->passive_checks = 0;
@ -61,6 +141,11 @@ class ObjectFlags {
return $flags;
}
/**
* Create a new ObjectFlags object that is in 'acknowledged' state
*
* @return ObjectFlags
*/
public static function ACKNOWLEDGED()
{
$flags = new ObjectFlags();
@ -68,25 +153,65 @@ class ObjectFlags {
return $flags;
}
/**
* Create a new ObjectFlags object that is in a downtime
*
* @return ObjectFlags
*/
public static function IN_DOWNTIME()
{
$flags = new ObjectFlags();
$flags->in_downtime = 1;
return $flags;
}
}
/**
* Internal class that adds an object scope on Fixture operations
*
* This class allows to use $fixture->addHost('host',0)->addService() instead('svc')
* of $fixture->addHost('host',0); $fixture->addService('host', 'svc') as it encapsulates
* the scope of the last called object and automatically adds it as the first parameter
* of the next call.
*
*/
class TestFixtureObjectClosure
{
/**
* The object (hostname or hostname/servicename pair) this scope represents
* @var String|array
*/
private $scope;
/**
* The Testfixture to operate on
* @var TestFixture
*/
private $environment;
/**
* Create a new scope using the TestFixture with the given host / service
* as the scope
*
* @param TestFixture $environment The testfixture to use for subsequent calls
* @param $scope The scope to prepend to all further calls
*/
public function __construct(TestFixture $environment, $scope)
{
$this->scope = $scope;
$this->environment = $environment;
}
/**
* Magic method that forwards all function calls to the environment
* but prepends the scope.
*
* A call func($arg1) to this class would be rewritten to $environment->func($scope, $arg1)
*
* @param string $string The method that should be called with this scope
* @param array $arguments The arguments the user passed to the function
* @return mixed The result of the function call
*/
public function __call($string, $arguments)
{
$callArg = array($this->scope);
@ -95,45 +220,176 @@ class TestFixtureObjectClosure
}
}
/**
* Create test-states that can be persisted to different backends
* using DataSourceTestSetup.
*
* This class provides not all fields used in monitoring, but the most
* important ones (and the ones that are missing should be added during
* developmen).
*
* Usage:
* <code>
* $fixture = new TestFixture();
* // adding a new critical, but acknowledged host
* $fixture->addHost("hostname", 1, ObjectFlags::ACKNOWLEDGED())
*
* // add a comment to the host (this has to be done before adding services)
* ->addComment("author", "comment text")
*
* // assign to hostgroup
* ->addToHostgroup("myHosts")
*
* // and add three services to this host
* ->addService("svc1", 0) // Service is ok
* ->addService("svc2", 1, ObjectFlags::PASSIVE) // service is warning and passive
* ->addService("svc3", 2, null, array("notes_url" => "test.html")) // critical with notes url
* ->addComment("author", "what a nice service comment") // add a comment to the service
* ->addToServicegroup("alwaysdown"); // add svc3 to servicegroup
*
* // Create the datasource from this fixture, here form MySQL
* $ds = new DataSourceTestSetup("mysql");
* $ds->setup();
* // insert fixture
* $ds->insert($fixture);
* </code>
*
*/
class TestFixture
{
/**
* Internal dataholder for all defined hosts
* @var array
*/
private $hosts = array();
/**
* Internal holder for all defined services
* @var array
*/
private $services = array();
/**
* Internal holder for all defined contacts
* @var array
*/
private $contacts = array();
/**
* Internal holder for all defined comments
* @var array
*/
private $comments = array();
/**
* Internal holder for all defined servicegroups
* @var array
*/
private $servicegroups = array();
/**
* Internal holder for all defined hostgroups
* @var array
*/
private $hostgroups = array();
/**
* Return array with all defined hostobjects
*
* @return array Returns an array of host-arrays, which have the following fields
* - 'name' : The name of the host
* - 'state' : The state of the host (0,1,2)
* - 'address' : The string representation of the address (127.0.0.1 as default)
* - 'flags' : An ObjectFlags object containing additional state information
* - 'icon_image' : The icon image of this host (default: 'icon.png')
* - 'notes_url' : The notes url of this host (default empty string)
* - 'action_url' : The action url of this host (default empty string)
* - 'contacts' : An array of contact objects (having 'name' as the most important field)
* - 'customvariables' : An associative "cv_name"=>"cv_value" array containing the customvariables
*/
public function getHosts()
{
return $this->hosts;
}
/**
* Return array with all defined service objects
*
* @return array Returns an array of service-arrays, which have the following fields
* - 'name' : The name of the service
* - 'host' : A reference to the hostobject
* - 'state' : The state of the service (0,1,2,3)
* - 'flags' : An ObjectFlags object containing additional state information
* - 'icon_image' : The icon image of this service (default: 'icon.png')
* - 'notes_url' : The notes url of this service (default empty string)
* - 'action_url' : The action url of this service (default empty string)
* - 'contacts' : An array of contact objects (having 'name' as the most important field)
* - 'customvariables' : An associative "cv_name"=>"cv_value" array containing the customvariables
*/
public function getServices()
{
return $this->services;
}
/**
* Return array with all defined contacts
*
* @return array Returns an array of contact-arrays, which have the following fields
* - 'alias' : The name of the contact
*/
public function getContacts()
{
return $this->contacts;
}
/**
* Return array with all defined servicegroups
*
* @return array Returns an array of group-arrays in the following format:
* - 'name' : The name of the group
* - 'members' : An array of service objects that belong to this group
*/
public function getServicegroups()
{
return $this->servicegroups;
}
/**
* Return an array with all defined hostgroups
*
* @return array Returns an array of group-arrays in the following format:
* - 'name' : The name of the group
* - 'members' : An array of host objects that belong to this group
*/
public function getHostgroups()
{
return $this->hostgroups;
}
/**
* Return an array of service and hostcomments
*
* @return array Returns an array of comment arrays in the following format:
* - 'service' (if servicecomment) : A reference to the service object this comment belongs to
* - 'host' (if hostcomment) : A reference to the host object this comment belongs to
* - 'author' : The author of this comment
* - 'text' : The comment text
*/
public function getComments()
{
return $this->comments;
}
/**
* Add a new host to this TestFixture
*
* @param string $name The name of the host to add
* @param int $state The state of the host to add (0,1,2)
* @param ObjectFlags $flags (optional) An @see ObjectFlags object defining additional state inforamtion
* @param array $additional (optional) An array with additional object fields
*
* @return TestFixtureObjectClosure The TestFixture with the newly added host as the scope
*/
public function addHost($name, $state, ObjectFlags $flags = null, array $additional = array()) {
if ($flags === null) {
$flags = new ObjectFlags();
@ -157,6 +413,17 @@ class TestFixture
return new TestFixtureObjectClosure($this, $name);
}
/**
* Add a new service to this TestFixture
*
* @param string $host The name of the host this service belongs to (must exist prior to service creation)
* @param string $name The name of the service to add
* @param int $state The state of the service to add (0,1,2,3)
* @param ObjectFlags $flags (optional) An @see ObjectFlags object defining additional state information
* @param array $additional (optional) An array with additional object fields
*
* @return TestFixtureObjectClosure The TestFixture with the newly added service as the scope
*/
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)) {
@ -187,6 +454,15 @@ class TestFixture
return new TestFixtureObjectClosure($this, array($host, $name));
}
/**
* Add a new comment to the host or service provided in $hostOrServiceHostPair
*
* @param string|array $hostOrServiceHostPair Either a string with the hostname or an array with the hostname
* as the first and the servicename as the second element
* @param $author The author for the coment
* @param $text The content of the comment
* @return TestFixtureObjectClosure The TestFixture with the comment owner as the scope
*/
public function addComment($hostOrServiceHostPair, $author, $text) {
if (is_array($hostOrServiceHostPair)) {
if (!isset($this->services[$hostOrServiceHostPair[0].';'.$hostOrServiceHostPair[1]])) {
@ -210,6 +486,14 @@ class TestFixture
return new TestFixtureObjectClosure($this, $hostOrServiceHostPair);
}
/**
* Assign a new contact to a host or service
*
* @param $hostOrServiceHostPair Either a string with the hostname or an array with the hostname
* as the first and the servicename as the second element
* @param $contactname The contactname to assign (will be created)
* @return TestFixtureObjectClosure The TestFixture with the host or service as the scope
*/
public function assignContact($hostOrServiceHostPair, $contactname) {
$this->contacts[$contactname] = array('alias' => $contactname);
if (is_array($hostOrServiceHostPair)) {
@ -228,6 +512,16 @@ class TestFixture
return new TestFixtureObjectClosure($this, $hostOrServiceHostPair);
}
/**
* Add a host to a hostgroup
*
* Create the new hostgroup if it not exists yet, otherwise just add the
* host to it
*
* @param string $host The name of the host to add to the hostgroup
* @param string $groupname The name of the hostgroup
* @return TestFixtureObjectClosure The TestFixture with the host as the scope
*/
public function addToHostgroup($host, $groupname) {
// check if in service scope
if (is_array($host)) {
@ -243,6 +537,16 @@ class TestFixture
return new TestFixtureObjectClosure($this, $host);
}
/**
* Add service to a servicegroup
*
* Create the new service if it not exists yet, otherwise just add the service
*
* @param array $serviceHostPair An array containing the hostname as the first and the
* servicename as the second element
* @param string $groupname The name of the servicegroup
* @return TestFixtureObjectClosure The TestFixture with the service as the scope
*/
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 ');
@ -254,7 +558,4 @@ class TestFixture
$this->servicegroups[$groupname]["members"][] = &$service;
return new TestFixtureObjectClosure($this, $serviceHostPair);
}
}

View File

@ -3,7 +3,10 @@
namespace Test\Monitoring\Testlib\DataSource\schemes;
/**
* Container class for Objectcache object snipptes
*
*/
class ObjectsCacheTemplates {
public static $HOST =<<<'EOF'

View File

@ -9,7 +9,10 @@
namespace Test\Monitoring\Testlib\DataSource\schemes;
/**
* Container class for Statusdat object snippets
*
*/
class StatusdatTemplates {
public static $HOST =<<<'EOF'

View File

@ -1,10 +1,33 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
use \Test\Monitoring\Testlib\DataSource\TestFixture;
/**
* Generic interface for Fixture insertion implementations
*
* These implementations can create Icinga-compatible Datatsources
* from TestFixture classes and are therefore rather free in their
* implementation
*
*/
interface InsertionStrategy {
/**
* Tell the class to use the given ressource as the
* connection identifier
*
* @param $connection A generic connection identifier,
* the concrete class depends on the implementation
*/
public function setConnection($connection);
/**
* Insert the passed fixture into the datasource and allow
* the icinga backends to query it.
*
* @param TestFixture $fixture
*/
public function insert(TestFixture $fixture);
}

View File

@ -1,9 +1,41 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
/**
* SetupStrategy implementation for MySQL based IDO-Backends
*
* This strategy creates a new MySQL Database and removes old ones
* if necessary. Per default the database user is icinga_unittest:icinga_unittest
* and the database to be created is also icinga_unittest. The user must
* have all Privileges on the test database, so its best to create him
* with:
*
* mysql -u root
* # CREATE USER `icinga_unittest`@`localhost` IDENTIFIED BY 'icinga_unittest';
* # CREATE DATABASE icinga_unittest;
* # GRANT ALL PRIVILEGES ON icinga_unittest.* TO `icinga_unittest`@`localhost`
*
**/
class MySQLSetupStrategy implements SetupStrategy {
/**
* Tears down any existing databases and creates a new blank IDO scheme.
*
* The database is created according to the passed version (or using the newest version if no version is provided),
* using the idoMySQL-%VERSION%.sql underneath the schemes folder.
* A \PDO Connection can be provided, if not the icinga_unittest default
* connection will be established and used.
*
* @param String $version An optional version to use as the db scheme
* @param \PDO $connection An optional connection to use instead of icinga_unittest
* @return \PDO The connection that has been created
*
* @throws \PDOException In case connecting to or creating the database fails
* @throws \Exception In case of an invalid/non-existing DB scheme
*/
public function setup($version = null, $connection = null)
{
if ($connection === null) {
@ -29,6 +61,13 @@ class MySQLSetupStrategy implements SetupStrategy {
return $connection;
}
/**
* Drops all tables from the connection via DROP TABLE
*
* @param \PDO $connection An optional connection to use, if none is
* given the icinga_unittest default will be used
*
*/
public function teardown($connection = null)
{
if ($connection === null) {

View File

@ -1,19 +1,60 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
use \Test\Monitoring\Testlib\DataSource\TestFixture;
class PDOInsertionStrategy {
/**
* TestFixture insertion implementation for PDO based backends
*
* This class allows to create the actual IDO databases from TestFixture
* classes using PDO.
*
*/
class PDOInsertionStrategy
{
/**
* Points to the (icinga) objectId of the next inserted object
* @var int
*/
private $objectId = 0;
/**
* The fixture that is being inserted by this object
* @var TestFixture
*/
private $fixture;
/**
* The database (PDO) connection to use for inserting
* @var \PDO
*/
private $connection;
/**
* The date format that will be used for inserting
* date values, see @link http://php.net/manual/en/function.date.php
* for possible values
*
* @var string
*/
public $datetimeFormat = "U";
/**
* @see InsertionStrategy::setConnection
*
* @param \PDO $connection The PDO connection to use
*/
public function setConnection($connection) {
$this->connection = $connection;
}
/**
* Insert the provided @see TestFixture into this database
*
* @param TestFixture $fixture The fixture to insert into the database
*/
public function insert(TestFixture $fixture)
{
$this->fixture = $fixture;
@ -28,7 +69,14 @@ class PDOInsertionStrategy {
$this->insertServicegroups();
}
/**
* Insert all hosts from the current fixture into the IDO Database
*
* This method updates the icinga_objects, icinga_hosts, icinga_hoststatus
* and icinga_customvariablestatus tables with the host values provided
* by the internal fixture (@see PDOInsertStrategy::insert)
*
*/
private function insertHosts()
{
$hosts = &$this->fixture->getHosts();
@ -83,6 +131,12 @@ class PDOInsertionStrategy {
}
}
/**
* Insert all services from the provided fixture into the IDO database
*
* This method updates the icinga_objects, icinga_services, icinga_servicestatus,
* icinga_service_contacts, icinga_customvariablestatus
*/
private function insertServices()
{
$services = $this->fixture->getServices();
@ -106,7 +160,7 @@ class PDOInsertionStrategy {
'INSERT INTO icinga_service_contacts (host_id, contact_object_id) VALUES (?, ?);'
);
$insertCVQuery = $this->connection->prepare(
'INSERT INTO icinga_customvariablestatus'.
'INSERT INTO icinga_customvariablestatus '.
'(object_id, varname, varvalue) VALUES (?, ?, ?)'
);
@ -139,6 +193,12 @@ class PDOInsertionStrategy {
}
}
/**
* Insert the contacts provided by the fixture into the database
*
* This method updates the icinga_objects and icinga_contacts tables
* according to the provided fixture
*/
private function insertContacts()
{
$insertObjectQuery = $this->connection->prepare(
@ -156,6 +216,12 @@ class PDOInsertionStrategy {
}
}
/**
* Insert comments provided by the fixture into the IDO database
*
* This method updates the icinga_comments table according to the provided
* fixture
*/
private function insertComments()
{ $comment_id=0;
$insertCommentsQuery = $this->connection->prepare(
@ -177,6 +243,12 @@ class PDOInsertionStrategy {
}
}
/**
* Insert hostgroups from the provided fixture into the IDO database
*
* This method updates the icinga_objects, icinga_hostgroups and icinga_hostgroup_members
* table with the values provide by the fixture
*/
private function insertHostgroups()
{
$insertObjectQuery = $this->connection->prepare(
@ -198,9 +270,14 @@ class PDOInsertionStrategy {
}
$this->objectId++;
}
}
/**
* Insert servicegroups from the provided fixture into the IDO database
*
* This method updates the icinga_objects, icinga_servicegroups and icinga_servicegroup_members
* table with the values provide by the fixture
*/
private function insertServicegroups()
{
$insertObjectQuery = $this->connection->prepare(

View File

@ -1,16 +1,34 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: moja
* Date: 7/16/13
* Time: 3:30 PM
* To change this template use File | Settings | File Templates.
*/
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
/***
* SetupStrategy implementation for PostgreSQL based IDO-Backends
*
* This strategy creates a new PostgreSQL Database and removes old ones
* if necessary. Per default the database user is icinga_unittest:icinga_unittest
* and the database to be created is also icinga_unittest.
**/
class PgSQLSetupStrategy implements SetupStrategy {
class PgSQLSetupStrategy {
/**
* Tears down any existing databases and creates a new blank IDO scheme.
*
* The database is created according to the passed version (or using the
* newest version if no version is provided), using the idoPgSQL-%VERSION%.sql
* underneath the schemes folder.
* A \PDO Connection can be provided, if not the icinga_unittest default
* connection will be established and used.
*
* @param String $version An optional version to use as the db scheme
* @param \PDO $connection An optional connection to use instead of icinga_unittest
* @return \PDO The connection that has been created
*
* @throws \PDOException In case connecting to or creating the database fails
* @throws \Exception In case of an invalid/non-existing DB scheme
*/
public function setup($version = null, $connection = null)
{
if ($connection === null) {
@ -35,6 +53,13 @@ class PgSQLSetupStrategy {
return $connection;
}
/**
* Drops all tables from the connection via DROP TABLE
*
* @param \PDO $connection An optional connection to use, if none is
* given the icinga_unittest default will be used
*
*/
public function teardown($connection = null)
{
if ($connection === null) {

View File

@ -1,8 +1,35 @@
<?php
namespace Test\Monitoring\Testlib\Datasource\Strategies;
/**
* Interface for setup classes that provide a clean starting point
* for @see InsertionStrategy classes to setup TestFixtures.
*
* As the backend for the setupstrategy can be anything from a database to
* a file to a socket, the resource is a mixed php type and the
* concrete requirement on the type is defined by the subclass implementing
* this interface.
*
*/
interface SetupStrategy {
/**
* Set up a new clean datastore icinga backends can use for querying data
*
* The resource parameter should be optional, as the setup class should provide
* a default setup method most testing setups can use
*
* @param String $version The optional version of the storage implementation to create
* @param mixed $resource The optional resource to use for setting up the storage
*
* @return mixed The connection or resource that has been created
*/
public function setup($version = null, $resource = null);
/**
* Remove all data from the given resource (or the default resource if none is given)
*
* @param mixed $resource
*/
public function teardown($resource = null);
}

View File

@ -1,11 +1,6 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: moja
* Date: 7/17/13
* Time: 10:18 AM
* To change this template use File | Settings | File Templates.
*/
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
use Test\Monitoring\Testlib\DataSource\schemes\ObjectsCacheTemplates;
@ -15,20 +10,69 @@ use \Test\Monitoring\Testlib\DataSource\schemes\StatusdatTemplates;
require_once(dirname(__FILE__).'/../schemes/ObjectsCacheTemplates.php');
require_once(dirname(__FILE__).'/../schemes/StatusdatTemplates.php');
/**
* An @see InsertionStrategy for creating status.dat and objects.cache
* files from a TestFixture
*
* This class helps testing status.dat backends by writing testfixtures
* to according objects.cache and status.dat files which then can be read
* by the Statusdat parser and used in tests.
*
* The templates for insertion can be found under schemes/objectsCacheTemplates.php
* and schemes/StatusdatTempaltes.php
*
*/
class StatusdatInsertionStrategy implements InsertionStrategy {
/**
* The status.dat filename to write the object-state to
* @var String
*/
private $statusDatFile;
/**
* The objects.cache filename to write the object structure to
* @var String
*/
private $objectsCacheFile;
/**
* The TestFixture that will be written to a status.dat compatible format
* @var TestFixture
*/
private $fixture;
/**
* The content of the status.dat file that will be written
* @var String
*/
private $statusDat;
/**
* The content of the objects.cache file that will be written
* @var String
*/
private $objectsCache;
/**
* Tell this object to use the status.dat/objects.cache file combination
* provided in $resource
*
* @param Array $ressource An associative array containing the following keys:
* - "status_file" : The location where to write the status.dat to
* - "objects_file" : The location to write the objects cache to
*/
public function setConnection($ressource)
{
$this->statusDatFile = $ressource['status_file'];
$this->objectsCacheFile = $ressource['objects_file'];
}
/**
* Insert the provided fixture into the status.dat and objects.cache files for testing
*
* @param TestFixture $fixture The fixture to create status.dat and objects.cache files from
*/
public function insert(TestFixture $fixture)
{
$this->fixture = $fixture;
@ -47,6 +91,11 @@ class StatusdatInsertionStrategy implements InsertionStrategy {
file_put_contents($this->objectsCacheFile, $this->objectsCache);
}
/**
* Insert the host monitoring state from the provided fixture to the internal
* statusdat string $statusDat
*
*/
private function insertHoststatus()
{
$hosts = $this->fixture->getHosts();
@ -70,6 +119,11 @@ class StatusdatInsertionStrategy implements InsertionStrategy {
}
}
/**
* Insert the host object state into the internal objects.cache representation
* $objectsCache
*
*/
private function insertHosts()
{
$hosts = $this->fixture->getHosts();
@ -92,6 +146,11 @@ class StatusdatInsertionStrategy implements InsertionStrategy {
}
}
/**
* Insert the service monitoring state from the provided fixture to the internal
* statusdat string $statusDat
*
*/
private function insertServicestatus()
{
$services = $this->fixture->getServices();
@ -124,6 +183,11 @@ class StatusdatInsertionStrategy implements InsertionStrategy {
}
/**
* Insert the service object state into the internal objects.cache representation
* $objectsCache
*
*/
private function insertServices()
{
$services = $this->fixture->getServices();
@ -143,6 +207,13 @@ class StatusdatInsertionStrategy implements InsertionStrategy {
}
}
/**
* Inserts a group object into the object.cache file
*
* @param String $type The type of the group ('host' or 'service')
* @param String $name The name of the group to insert
* @param array $members A String array of the members names to use
*/
private function insertGroup($type, $name, array $members)
{
$groupDefinition = str_replace(
@ -150,13 +221,17 @@ class StatusdatInsertionStrategy implements InsertionStrategy {
'{{TYPE}}', '{{NAME}}', '{{MEMBERS}}'
),
array("\t",
'host', $name, implode(",", $members)
$type, $name, implode(",", $members)
),
ObjectsCacheTemplates::$GROUP
);
$this->objectsCache .= "\n".$groupDefinition;
}
/**
* Insert all hostgroups from the fixtures into the objects.cache
*
*/
private function insertHostgroups()
{
$hostgroups = $this->fixture->getHostgroups();
@ -169,6 +244,10 @@ class StatusdatInsertionStrategy implements InsertionStrategy {
}
}
/**
* Inserts all servicegroups from the fixtures into the objects.cache
*
*/
private function insertServicegroups()
{
$servicegroups = $this->fixture->getServicegroups();
@ -178,10 +257,15 @@ class StatusdatInsertionStrategy implements InsertionStrategy {
$memberNames[] = $member["host"]["name"];
$memberNames[] = $member["name"];
}
$this->insertGroup("service", $serviegroup["name"], $memberNames);
$this->insertGroup("service", $servicegroup["name"], $memberNames);
}
}
/**
* Inserts all comments from the fixtures into the status.dat string
* $statusDat
*
*/
private function insertComments()
{
$comments = $this->fixture->getComments();
@ -209,8 +293,6 @@ class StatusdatInsertionStrategy implements InsertionStrategy {
);
}
$this->statusDat .= "\n".$commentDefinition;
}
}
}

View File

@ -1,10 +1,23 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Test\Monitoring\Testlib\Datasource\Strategies;
/**
* SetupStrategy for status dat.
*
* This class is used for setting up a test enviromnent for querying
* statusdat fixtures.
*
*/
class StatusdatSetupStrategy implements SetupStrategy {
/**
* Recursively require all php files underneath $folder
*
* @param String $folder The folder to require
*/
private function requireFolder($folder)
{
$files = scandir($folder);
@ -20,6 +33,13 @@ class StatusdatSetupStrategy implements SetupStrategy {
}
}
/**
* Require all classes needed to work with the status.dat Reader
*
* This includes the Status.dat Reader and Parser classes
* from Icinga/PRotocol as well as a few dependencies (Logging, Zend_Cache)
*
*/
private function requireStatusDat()
{
$moduleDir = realpath(dirname(__FILE__)."/../../../../../");
@ -33,9 +53,21 @@ class StatusdatSetupStrategy implements SetupStrategy {
require_once($base."/Query/IQueryPart.php");
require_once($base."/IReader.php");
$this->requireFolder($base);
}
/**
* Create the status.dat and objects.cache files for using testfixtures
*
* Remove existing files for status.dat testfixtures and create new
* (empty) files at /tmp/ when no resource is given.
*
* @param String $version The version to use, will be ignored
* @param array $resource An optional associative array pointing to the
* objects_cache and status.dat files. The keys are as following:
* - "status_file" : Path to the status.dat to remove and recreate
* - "objects_file" : Path to the objects.cache file to remove and recreate
* @return array An path array (see $resource) that contains the used file paths
*/
public function setup($version = null, $resource = null)
{
if ($resource == null) {
@ -51,9 +83,23 @@ class StatusdatSetupStrategy implements SetupStrategy {
return $resource;
}
/**
* Remove test status.dat and objects.cache files
*
* @param array $resource An optional associative array pointing to the
* objects_cache and status.dat files. The keys are as following:
* - "status_file" : Path to the status.dat to remove
* - "objects_file" : Path to the objects.cache file to remove
*/
public function teardown($resource = null)
{
if ($resource == null) {
$resource = array(
"status_file" => "/tmp/teststatus.dat",
"objects_file" => "/tmp/testobjects.cache"
);
}
if (file_exists($resource["status_file"])) {
unlink($resource["status_file"]);
}