Test tools reintroduced as a separate folder, most of the files being excluded from the std build

SVN:trunk[840]
This commit is contained in:
Romain Quetiez
2010-09-13 11:58:09 +00:00
parent 555dd76ade
commit 0a5baa85f4
6 changed files with 2826 additions and 37 deletions

View File

@@ -1,37 +0,0 @@
<?php
//
// phpMyORM configuration file
//
// To be manually edited (or generated by the configuration wizard)
//
// The file is used in MetaModel::LoadConfig() which does all the necessary initialization job
//
$MySettings = array(
'db_host' => 'localhost',
'db_user' => 'itop',
'db_pwd' => '1T0p',
'db_name' => 'itopv06',
'db_subname' => '', // use it to differentiate two applications instances running on the same DB
);
// Modules: file names should be specified as a absolute paths
$MyModules = array(
'application' => array (
'../application/menunode.class.inc.php',
'../application/audit.rule.class.inc.php',
// to be continued...
),
'business' => array (
// to be continued...
),
'addons' => array (
'user rights' => '../addons/userrights/userrightsprofile.class.inc.php',
// other modules to come later
)
);
?>

8
test/exclude.txt Normal file
View File

@@ -0,0 +1,8 @@
#
# The following source files are not re-distributed with the "build" of the application
# since they are used solely for constructing other files during the build process
#
config-test-farm.php
test.class.inc.php
test.php
testlist.inc.php

557
test/test.class.inc.php Normal file
View File

@@ -0,0 +1,557 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Core automated tests - basics
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once('../core/coreexception.class.inc.php');
require_once('../core/attributedef.class.inc.php');
require_once('../core/filterdef.class.inc.php');
require_once('../core/stimulus.class.inc.php');
require_once('../core/MyHelpers.class.inc.php');
require_once('../core/expression.class.inc.php');
require_once('../core/cmdbsource.class.inc.php');
require_once('../core/sqlquery.class.inc.php');
require_once('../core/log.class.inc.php');
require_once('../core/kpi.class.inc.php');
require_once('../core/dbobject.class.php');
require_once('../core/dbobjectsearch.class.php');
require_once('../core/dbobjectset.class.php');
require_once('../application/cmdbabstract.class.inc.php');
require_once('../core/userrights.class.inc.php');
require_once('../webservices/webservices.class.inc.php');
// Just to differentiate programmatically triggered exceptions and other kind of errors (usefull?)
class UnitTestException extends Exception
{}
/**
* Improved display of the backtrace
*
* @package iTopORM
*/
class ExceptionFromError extends Exception
{
public function getTraceAsHtml()
{
$aBackTrace = $this->getTrace();
return MyHelpers::get_callstack_html(0, $this->getTrace());
// return "<pre>\n".$this->getTraceAsString()."</pre>\n";
}
}
/**
* Test handler API and basic helpers
*
* @package iTopORM
*/
abstract class TestHandler
{
protected $m_aSuccesses;
protected $m_aWarnings;
protected $m_aErrors;
protected $m_sOutput;
public function __construct()
{
$this->m_aSuccesses = array();
$this->m_aWarnings = array();
$this->m_aErrors = array();
}
static public function GetName() {return "fooname";}
static public function GetDescription(){return "foodesc";}
protected function DoPrepare() {return true;}
abstract protected function DoExecute();
protected function DoCleanup() {return true;}
protected static function DumpVariable($var)
{
echo "<pre class=\"vardump\">\n";
print_r($var);
echo "</pre>\n";
}
protected function ReportSuccess($sMessage, $sSubtestId = '')
{
$this->m_aSuccesses[] = $sMessage;
}
protected function ReportWarning($sMessage, $sSubtestId = '')
{
$this->m_aWarnings[] = $sMessage;
}
protected function ReportError($sMessage, $sSubtestId = '')
{
$this->m_aErrors[] = $sMessage;
}
public function GetResults()
{
return $this->m_aSuccesses;
}
public function GetWarnings()
{
return $this->m_aWarnings;
}
public function GetErrors()
{
return $this->m_aErrors;
}
public function GetOutput()
{
return $this->m_sOutput;
}
public function error_handler($errno, $errstr, $errfile, $errline)
{
// Note: return false to call the default handler (stop the program if an error)
switch ($errno)
{
case E_USER_ERROR:
$this->ReportError($errstr);
//throw new ExceptionFromError("Fatal error in line $errline of file $errfile: $errstr");
break;
case E_USER_WARNING:
$this->ReportWarning($errstr);
break;
case E_USER_NOTICE:
$this->ReportWarning($errstr);
break;
default:
$this->ReportWarning("Unknown error type: [$errno] $errstr in $errfile at $errline");
echo "Unknown error type: [$errno] $errstr in $errfile at $errline<br />\n";
break;
}
return true; // do not call the default handler
}
public function Execute()
{
ob_start();
set_error_handler(array($this, 'error_handler'));
try
{
$this->DoPrepare();
$this->DoExecute();
}
catch (ExceptionFromError $e)
{
$this->ReportError($e->getMessage().' - '.$e->getTraceAsHtml());
}
catch (CoreException $e)
{
//$this->ReportError($e->getMessage());
//$this->ReportError($e->__tostring());
$this->ReportError($e->getMessage().' - '.$e->getTraceAsHtml());
}
catch (Exception $e)
{
//$this->ReportError($e->getMessage());
//$this->ReportError($e->__tostring());
$this->ReportError('class '.get_class($e).' --- '.$e->getMessage().' - '.$e->getTraceAsString());
}
restore_error_handler();
$this->m_sOutput = ob_get_clean();
return (count($this->GetErrors()) == 0);
}
}
/**
* Test to execute a piece of code (checks if an error occurs)
*
* @package iTopORM
*/
abstract class TestFunction extends TestHandler
{
// simply overload DoExecute (temporary)
}
/**
* Test to execute a piece of code (checks if an error occurs)
*
* @package iTopORM
*/
abstract class TestWebServices extends TestHandler
{
// simply overload DoExecute (temporary)
static protected function DoPostRequestAuth($sRelativeUrl, $aData, $sLogin = 'admin', $sPassword = 'admin', $sOptionnalHeaders = null)
{
$aDataAndAuth = $aData;
// To be changed to use basic authentication
$aDataAndAuth['operation'] = 'login';
$aDataAndAuth['auth_user'] = $sLogin;
$aDataAndAuth['auth_pwd'] = $sPassword;
$sHost = $_SERVER['HTTP_HOST'];
$sRawPath = $_SERVER['SCRIPT_NAME'];
$sPath = dirname($sRawPath);
$sUrl = "http://$sHost/$sPath/$sRelativeUrl";
return self::DoPostRequest($sUrl, $aDataAndAuth, $sOptionnalHeaders);
}
// Source: http://netevil.org/blog/2006/nov/http-post-from-php-without-curl
// originaly named after do_post_request
// Partially adapted to our coding conventions
static protected function DoPostRequest($sUrl, $aData, $sOptionnalHeaders = null)
{
// $sOptionnalHeaders is a string containing additional HTTP headers that you would like to send in your request.
$sData = http_build_query($aData);
$aParams = array('http' => array(
'method' => 'POST',
'content' => $sData,
'header'=> "Content-type: application/x-www-form-urlencoded\r\nContent-Length: ".strlen($sData)."\r\n",
));
if ($sOptionnalHeaders !== null)
{
$aParams['http']['header'] .= $sOptionnalHeaders;
}
$ctx = stream_context_create($aParams);
$fp = @fopen($sUrl, 'rb', false, $ctx);
if (!$fp)
{
global $php_errormsg;
if (isset($php_errormsg))
{
throw new Exception("Problem with $sUrl, $php_errormsg");
}
else
{
throw new Exception("Problem with $sUrl");
}
}
$response = @stream_get_contents($fp);
if ($response === false)
{
throw new Exception("Problem reading data from $sUrl, $php_errormsg");
}
return $response;
}
}
/**
* Test to execute a piece of code (checks if an error occurs)
*
* @package iTopORM
*/
abstract class TestSoapWebService extends TestHandler
{
// simply overload DoExecute (temporary)
function __construct()
{
parent::__construct();
}
}
/**
* Test to check that a function outputs some values depending on its input
*
* @package iTopORM
*/
abstract class TestFunctionInOut extends TestFunction
{
// abstract static public function GetCallSpec(); // parameters to call_user_func
// abstract static public function GetInOut(); // array of input => output
protected function DoExecute()
{
$aTests = $this->GetInOut();
if (is_array($aTests))
{
foreach ($aTests as $iTestId => $aTest)
{
$ret = call_user_func_array($this->GetCallSpec(), $aTest['args']);
if ($ret != $aTest['output'])
{
// Note: to be improved to cope with non string parameters
$this->ReportError("Found '$ret' while expecting '".$aTest['output']."'", $iTestId);
}
else
{
$this->ReportSuccess("Found the expected output '$ret'", $iTestId);
}
}
}
else
{
$ret = call_user_func($this->GetCallSpec());
$this->ReportSuccess('Finished successfully');
}
}
}
/**
* Test to check an URL (Searches for Error/Warning/Etc keywords)
*
* @package iTopORM
*/
abstract class TestUrl extends TestHandler
{
// abstract static public function GetUrl();
// abstract static public function GetErrorKeywords();
// abstract static public function GetWarningKeywords();
protected function DoExecute()
{
return true;
}
}
/**
* Test to check a user management module
*
* @package iTopORM
*/
abstract class TestUserRights extends TestHandler
{
protected function DoExecute()
{
return true;
}
}
/**
* Test to execute a scenario on a given DB
*
* @package iTopORM
*/
abstract class TestScenarioOnDB extends TestHandler
{
// abstract static public function GetDBHost();
// abstract static public function GetDBUser();
// abstract static public function GetDBPwd();
// abstract static public function GetDBName();
protected function DoPrepare()
{
$sDBHost = $this->GetDBHost();
$sDBUser = $this->GetDBUser();
$sDBPwd = $this->GetDBPwd();
$sDBName = $this->GetDBName();
CMDBSource::Init($sDBHost, $sDBUser, $sDBPwd);
CMDBSource::SetCharacterSet();
if (CMDBSource::IsDB($sDBName))
{
CMDBSource::DropDB($sDBName);
}
CMDBSource::CreateDB($sDBName);
}
protected function DoCleanup()
{
// CMDBSource::DropDB($this->GetDBName());
}
}
/**
* Test to use a business model on a given DB
*
* @package iTopORM
*/
abstract class TestBizModel extends TestHandler
{
// abstract static public function GetDBSubName();
// abstract static public function GetBusinessModelFile();
// abstract static public function GetConfigFile();
protected function DoPrepare()
{
MetaModel::Startup($this->GetConfigFile());
// #@# Temporary disabled by Romain
// MetaModel::CheckDefinitions();
// something here to create records... but that's another story
}
protected $m_oChange;
protected function ObjectToDB($oNew, $bReload = false)
{
list($bRes, $aIssues) = $oNew->CheckToWrite();
if (!$bRes)
{
throw new CoreException('Could not create object, unexpected values', array('issues' => $aIssues));
}
if ($oNew instanceof CMDBObject)
{
if (!isset($this->m_oChange))
{
new CMDBChange();
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$oMyChange->Set("userinfo", "Someone doing some tests");
$iChangeId = $oMyChange->DBInsertNoReload();
$this->m_oChange = $oMyChange;
}
if ($bReload)
{
$iId = $oNew->DBInsertTracked($this->m_oChange);
}
else
{
$iId = $oNew->DBInsertTrackedNoReload($this->m_oChange);
}
}
else
{
if ($bReload)
{
$iId = $oNew->DBInsert();
}
else
{
$iId = $oNew->DBInsertNoReload();
}
}
return $iId;
}
protected function ResetDB()
{
if (MetaModel::DBExists(false))
{
MetaModel::DBDrop();
}
MetaModel::DBCreate();
}
static protected function show_list($oObjectSet)
{
$oObjectSet->Rewind();
$aData = array();
while ($oItem = $oObjectSet->Fetch())
{
$aValues = array();
foreach(MetaModel::GetAttributesList(get_class($oItem)) as $sAttCode)
{
$aValues[$sAttCode] = $oItem->GetAsHTML($sAttCode);
}
//echo $oItem->GetKey()." => ".implode(", ", $aValues)."</br>\n";
$aData[] = $aValues;
}
echo MyHelpers::make_table_from_assoc_array($aData);
}
static protected function search_and_show_list(DBObjectSearch $oMyFilter)
{
$oObjSet = new CMDBObjectSet($oMyFilter);
echo $oMyFilter->__DescribeHTML()."' - Found ".$oObjSet->Count()." items.</br>\n";
self::show_list($oObjSet);
}
static protected function search_and_show_list_from_oql($sOQL)
{
echo $sOQL."...<br/>\n";
$oNewFilter = DBObjectSearch::FromOQL($sOQL);
self::search_and_show_list($oNewFilter);
}
}
/**
* Test to execute a scenario common to any business model (tries to build all the possible queries, etc.)
*
* @package iTopORM
*/
abstract class TestBizModelGeneric extends TestBizModel
{
static public function GetName()
{
return 'Full test on a given business model';
}
static public function GetDescription()
{
return 'Systematic tests: gets each and every existing class and tries every attribute, search filters, etc.';
}
protected function DoPrepare()
{
parent::DoPrepare();
if (!MetaModel::DBExists(false))
{
MetaModel::DBCreate();
}
// something here to create records... but that's another story
}
protected function DoExecute()
{
foreach(MetaModel::GetClasses() as $sClassName)
{
if (MetaModel::HasTable($sClassName)) continue;
$oNobody = MetaModel::GetObject($sClassName, 123);
$oBaby = new $sClassName;
$oFilter = new DBObjectSearch($sClassName);
// Challenge reversibility of OQL / filter object
//
$sExpr1 = $oFilter->ToOQL();
$oNewFilter = DBObjectSearch::FromOQL($sExpr1);
$sExpr2 = $oNewFilter->ToOQL();
if ($sExpr1 != $sExpr2)
{
$this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
}
// Use the filter (perform the query)
//
$oSet = new CMDBObjectSet($oFilter);
$this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
}
return true;
}
}
?>

157
test/test.php Normal file
View File

@@ -0,0 +1,157 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Core test page
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
?>
<style>
.vardump {
font-size:8pt;
line-height:100%;
}
</style>
<?
///////////////////////////////////////////////////////////////////////////////
// Helpers
///////////////////////////////////////////////////////////////////////////////
function ReadMandatoryParam($sName)
{
$value = utils::ReadParam($sName, null);
if (is_null($value))
{
echo "<p>Missing mandatory argument <b>$sName</b></p>";
exit;
}
return $value;
}
function IsAValidTestClass($sClassName)
{
// Must be a child of TestHandler
//
if (!is_subclass_of($sClassName, 'TestHandler')) return false;
// Must not be abstract
//
$oReflectionClass = new ReflectionClass($sClassName);
if (!$oReflectionClass->isInstantiable()) return false;
return true;
}
function DisplayEvents($aEvents, $sTitle)
{
echo "<h4>$sTitle</h4>\n";
if (count($aEvents) > 0)
{
echo "<ul>\n";
foreach ($aEvents as $sEvent)
{
echo "<li>$sEvent</li>\n";
}
echo "</ul>\n";
}
else
{
echo "<p>none</p>\n";
}
}
///////////////////////////////////////////////////////////////////////////////
// Main
///////////////////////////////////////////////////////////////////////////////
require_once('../application/utils.inc.php');
require_once('../core/test.class.inc.php');
require_once('./testlist.inc.php');
require_once('../core/cmdbobject.class.inc.php');
$sTodo = utils::ReadParam("todo", "");
if ($sTodo == '')
{
// Show the list of tests
//
echo "<h3>Existing tests</h3>\n";
echo "<ul>\n";
foreach (get_declared_classes() as $sClassName)
{
if (!IsAValidTestClass($sClassName)) continue;
$sName = call_user_func(array($sClassName, 'GetName'));
$sDescription = call_user_func(array($sClassName, 'GetDescription'));
echo "<li><a href=\"?todo=exec&testid=$sClassName\">$sName</a> ($sDescription)</li\n";
}
echo "</ul>\n";
}
else if ($sTodo == 'exec')
{
// Execute a test
//
$sTestClass = ReadMandatoryParam("testid");
if (!IsAValidTestClass($sTestClass))
{
echo "<p>Wrong value for testid, expecting a valid class name</p>\n";
}
else
{
$oTest = new $sTestClass();
echo "<h3>Testing: ".$oTest->GetName()."</h3>\n";
$bRes = $oTest->Execute();
}
/*
MyHelpers::var_dump_html($oTest->GetResults());
MyHelpers::var_dump_html($oTest->GetWarnings());
MyHelpers::var_dump_html($oTest->GetErrors());
*/
if ($bRes)
{
echo "<p>Success :-)</p>\n";
DisplayEvents($oTest->GetResults(), 'Results');
}
else
{
echo "<p>Failure :-(</p>\n";
}
DisplayEvents($oTest->GetErrors(), 'Errors');
DisplayEvents($oTest->GetWarnings(), 'Warnings');
// Render the output
//
echo "<h4>Actual output</h4>\n";
echo "<div style=\"border: dashed; background-color:light-grey;\">\n";
echo $oTest->GetOutput();
echo "</div>\n";
}
else
{
}
?>

2104
test/testlist.inc.php Normal file

File diff suppressed because it is too large Load Diff