浏览代码

Removed automatic test tools (separate module)

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@838 a333f486-631f-4898-b8df-5754b55c2be0
romainq 14 年之前
父节点
当前提交
a5387e46f7
共有 3 个文件被更改,包括 0 次插入2818 次删除
  1. 0 557
      core/test.class.inc.php
  2. 0 157
      pages/test.php
  3. 0 2104
      pages/testlist.inc.php

+ 0 - 557
core/test.class.inc.php

@@ -1,557 +0,0 @@
-<?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('coreexception.class.inc.php');
-require_once('attributedef.class.inc.php');
-require_once('filterdef.class.inc.php');
-require_once('stimulus.class.inc.php');
-require_once('MyHelpers.class.inc.php');
-
-require_once('expression.class.inc.php');
-require_once('cmdbsource.class.inc.php');
-require_once('sqlquery.class.inc.php');
-
-require_once('log.class.inc.php');
-require_once('kpi.class.inc.php');
-
-require_once('dbobject.class.php');
-require_once('dbobjectsearch.class.php');
-require_once('dbobjectset.class.php');
-
-require_once('../application/cmdbabstract.class.inc.php');
-
-require_once('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;
-	}
-}
-
-
-?>

+ 0 - 157
pages/test.php

@@ -1,157 +0,0 @@
-<?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
-{
-}
-
-
-?>

+ 0 - 2104
pages/testlist.inc.php

@@ -1,2104 +0,0 @@
-<?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 list
- *
- * @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
- */
-
-
-class TestSQLQuery extends TestScenarioOnDB
-{
-	static public function GetName() {return 'SQLQuery';}
-	static public function GetDescription() {return 'SQLQuery does not depend on the rest of the framework, therefore it makes sense to have a separate test framework for it';}
-
-	static public function GetDBHost() {return 'localhost';}
-	static public function GetDBUser() {return 'root';}
-	static public function GetDBPwd() {return '';}
-	static public function GetDBName() {return 'TestSQLQuery';}
-	static public function GetDBSubName() {return 'taratata';}
-
-
-	protected function DoPrepare()
-	{
-		parent::DoPrepare();
-		cmdbSource::CreateTable('CREATE TABLE `myTable` (myKey INT(11) NOT NULL auto_increment, column1 VARCHAR(255), column2 VARCHAR(255), PRIMARY KEY (`myKey`)) ENGINE = '.MYSQL_ENGINE);
-		cmdbSource::CreateTable('CREATE TABLE `myTable1` (myKey1 INT(11) NOT NULL auto_increment, column1_1 VARCHAR(255), column1_2 VARCHAR(255), PRIMARY KEY (`myKey1`)) ENGINE = '.MYSQL_ENGINE);
-		cmdbSource::CreateTable('CREATE TABLE `myTable2` (myKey2 INT(11) NOT NULL auto_increment, column2_1 VARCHAR(255), column2_2 VARCHAR(255), PRIMARY KEY (`myKey2`)) ENGINE = '.MYSQL_ENGINE);
-	}
-
-	protected function DoExecute()
-	{
-		$oQuery = new SQLQuery(
-			$sTable = 'myTable',
-			$sTableAlias = 'myTableAlias',
-			$aFields = array('column1'=>new FieldExpression('column1', 'myTableAlias'), 'column2'=>new FieldExpression('column2', 'myTableAlias')),
-			$oCondition = new BinaryExpression(new FieldExpression('column1', 'myTableAlias'), 'LIKE', new ScalarExpression('trash')),
-			$aFullTextNeedles = array('column1'),
-			$bToDelete = false,
-			$aValues = array()
-		);
-		$oQuery->AddCondition(Expression::FromOQL('DATE(NOW() - 1200 * 2) > \'2008-07-31\''));
-
-		$oSubQuery1 = new SQLQuery(
-			$sTable = 'myTable1',
-			$sTableAlias = 'myTable1Alias',
-			$aFields = array('column1_1'=>new FieldExpression('column1', 'myTableAlias'), 'column1_2'=>new FieldExpression('column1', 'myTableAlias')),
-			$oCondition = new TrueSQLExpression,
-			$aFullTextNeedles = array(),
-			$bToDelete = false,
-			$aValues = array()
-		);
-
-		$oSubQuery2 = new SQLQuery(
-			$sTable = 'myTable2',
-			$sTableAlias = 'myTable2Alias',
-			$aFields = array('column2_1'=>new FieldExpression('column2', 'myTableAlias'), 'column2_2'=>new FieldExpression('column2', 'myTableAlias')),
-			$oCondition = new TrueSQLExpression,
-			$aFullTextNeedles = array(),
-			$bToDelete = false,
-			$aValues = array()
-		);
-
-		$oQuery->AddInnerJoin($oSubQuery1, 'column1', 'column1_1');
-		$oQuery->AddLeftJoin($oSubQuery2, 'column2', 'column2_2');
-		
-		$oQuery->DisplayHtml();
-		$oQuery->RenderDelete();
-		$oQuery->RenderUpdate();
-		echo '<p>'.$oQuery->RenderSelect().'</p>';
-		$oQuery->RenderSelect(array('column1'));
-		$oQuery->RenderSelect(array('column1', 'column2'));
-	}
-}
-
-class TestOQLParser extends TestFunction
-{
-	static public function GetName() {return 'Check OQL parsing';}
-	static public function GetDescription() {return 'Attempts a series of queries, and in particular those with a bad syntax';}
-
-	protected function CheckQuery($sQuery, $bIsCorrectQuery)
-	{
-		$oOql = new OqlInterpreter($sQuery);
-		try
-		{
-			$oTrash = $oOql->Parse(); // Not expecting a given format, otherwise use ParseExpression/ParseObjectQuery/ParseValueSetQuery
-			self::DumpVariable($oTrash);
-		}
-		catch (OQLException $OqlException)
-		{
-			if ($bIsCorrectQuery)
-			{
-				echo "<p>More info on this unexpected failure:<br/>".$OqlException->getHtmlDesc()."</p>\n";
-				throw $OqlException;
-				return false;
-			}
-			else
-			{
-				// Everything is fine :-)
-				echo "<p>More info on this expected failure:<br/>".$OqlException->getHtmlDesc()."</p>\n";
-				return true;
-			}
-		}
-		// The query was correctly parsed, was it expected to be correct ?
-		if ($bIsCorrectQuery)
-		{
-			return true;
-		}
-		else
-		{
-			throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)");
-			return false;
-		}
-	}
-
-	protected function TestQuery($sQuery, $bIsCorrectQuery)
-	{
-		if (!$this->CheckQuery($sQuery, $bIsCorrectQuery))
-		{
-			return false;
-		}
-		return true;
-	}
-
-	public function DoExecute()
-	{
-		$aQueries = array(
-			'SELECT toto' => true,
-			'SELECT toto WHERE toto.a = 1' => true,
-			'SELECT toto WHERE toto.a=1' => true,
-			'SELECT toto WHERE toto.a = "1"' => true,
-			'SELECT toto WHHHERE toto.a = "1"' => false,
-			'SELECT toto WHERE toto.a == "1"' => false,
-			'SELECT toto WHERE toto.a % 1' => false,
-			//'SELECT toto WHERE toto.a LIKE 1' => false,
-			'SELECT toto WHERE toto.a like \'arg\'' => false,
-			'SELECT toto WHERE toto.a NOT LIKE "That\'s it"' => true,
-			'SELECT toto WHERE toto.a NOT LIKE "That\'s "it""' => false,
-			'SELECT toto WHERE toto.a NOT LIKE "That\'s \\"it\\""' => true,
-			'SELECT toto WHERE toto.a NOT LIKE \'That"s it\'' => true,
-			'SELECT toto WHERE toto.a NOT LIKE \'That\'s it\'' => false,
-			'SELECT toto WHERE toto.a NOT LIKE \'That\\\'s it\'' => true,
-			'SELECT toto WHERE toto.a NOT LIKE "blah \\ truc"' => false,
-			'SELECT toto WHERE toto.a NOT LIKE "blah \\\\ truc"' => true,
-			'SELECT toto WHERE toto.a NOT LIKE \'blah \\ truc\'' => false,
-			'SELECT toto WHERE toto.a NOT LIKE \'blah \\\\ truc\'' => true,
-
-			'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true,
-			'SELECT toto WHERE toto.a NOT LIKE "\\""' => true,
-			'SELECT toto WHERE toto.a NOT LIKE "\\"\\\\"' => true,
-			'SELECT toto WHERE toto.a NOT LIKE "\\\\\\""' => true,
-			'SELECT toto WHERE toto.a NOT LIKE ""' => true,
-			'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true,
-			"SELECT UserRightsMatrixClassGrant WHERE UserRightsMatrixClassGrant.class = 'lnkContactRealObject' AND UserRightsMatrixClassGrant.action = 'modify' AND UserRightsMatrixClassGrant.login = 'Denis'" => true,
-			"SELECT A WHERE A.col1 = 'lit1' AND A.col2 = 'lit2' AND A.col3 = 'lit3'" => true,
-
-			'SELECT toto WHERE toto.a NOT LIKE "blah" AND toto.b LIKE "foo"' => true,
-
-			//'SELECT toto WHERE toto.a > \'asd\'' => false,
-			'SELECT toto WHERE toto.a = 1 AND toto.b LIKE "x" AND toto.f >= 12345' => true,
-			'SELECT Device JOIN Site ON Device.site = Site.id' => true,
-			'SELECT Device JOIN Site ON Device.site = Site.id JOIN Country ON Site.location = Country.id' => true,
-
-			"SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 = 123 AND B.col1 = 'aa') OR (A.col3 = 'zzz' AND B.col4 > 100)" => true,
-			"SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 = B.col2 AND B.col1 = A.col2) OR (A.col3 = '' AND B.col4 > 100)" => true,
-			"SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + B.col2 * B.col1 = A.col2" => true,
-			"SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + (B.col2 * B.col1) = A.col2" => true,
-			"SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 + B.col2) * B.col1 = A.col2" => true,
-
-			'SELECT Device AS D_ JOIN Site AS S_ ON D_.site = S_.id WHERE S_.country = "Francia"' => true,
-
-			// Several objects in a row...
-			//
-			'SELECT A FROM A' => true,
-			'SELECT A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
-			'SELECT A FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
-			'SELECT B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
-			'SELECT A,B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
-			'SELECT A, B FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
-			'SELECT B,A FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => true,
-			'SELECT  A, B,C FROM A JOIN B ON A.myB = B.id' => false,
-			'SELECT C FROM A JOIN B ON A.myB = B.id WHERE A.col1 = 2' => false,
-		);
-
-		$iErrors = 0;
-
-		foreach($aQueries as $sQuery => $bIsCorrectQuery)
-		{
-			$sIsOk = $bIsCorrectQuery ? 'good' : 'bad';
-			echo "<h4>Testing query: $sQuery ($sIsOk)</h4>\n";
-			$bRet = $this->TestQuery($sQuery, $bIsCorrectQuery);
-			if (!$bRet) $iErrors++;
-		}
-		
-		return ($iErrors == 0);
-	}
-}
-
-
-class TestCSVParser extends TestFunction
-{
-	static public function GetName() {return 'Check CSV parsing';}
-	static public function GetDescription() {return 'Loads a set of CSV data';}
-
-	public function DoExecute()
-	{
-		$sDataFile = '?field1?;?field2?;?field3?
-?a?;?b?;?c?
-a;b;c
- ? a ? ; ? b ? ; ? c ? 
- a ; b ; c 
-??;??;??
-;;
-?a"?;?b?;?c?
-?a1
-a2?;?b?;?c?
-?a1,a2?;?b?;?c?
-?a?;?b?;?c1,",c2
-,c3?
-?a?;?b?;?ouf !?
-    Espace sur la fin ; 1234; e@taloc.com ';
-
-		self::DumpVariable($sDataFile);
-
-		$aExpectedResult = array(
-			//array('field1', 'field2', 'field3'),
-			array('a', 'b', 'c'),
-			array('a', 'b', 'c'),
-			array(' a ', ' b ', ' c '),
-			array('a', 'b', 'c'),
-			array('', '', ''),
-			array('', '', ''),
-			array('a"', 'b', 'c'),
-			array("a1\na2", 'b', 'c'),
-			array('a1,a2', 'b', 'c'),
-			array('a', 'b', "c1,\",c2\n,c3"),
-			array('a', 'b', 'ouf !'),
-			array('Espace sur la fin', '1234', 'e@taloc.com'),
-		);
-	
-		$oCSVParser = new CSVParser($sDataFile, ';', '?');
-		$aData = $oCSVParser->ToArray(1, null, 0);
-
-		$iIssues = 0;
-
-		echo "<table border=\"1\">\n";
-		foreach ($aData as $iRow => $aRow)
-		{
-			echo "<tr>\n";
-			foreach ($aRow as $iCol => $sCell)
-			{
-				if (empty($sCell))
-				{
-					$sCellValue = '&nbsp;';
-				}
-				else
-				{
-					$sCellValue = htmlentities($sCell);
-				}
-
-				if (!isset($aExpectedResult[$iRow][$iCol]))
-				{
-					$iIssues++;
-					$sCellValue = "<span style =\"color: red; background-color: grey;\">$sCellValue</span>";
-				}
-				elseif ($aExpectedResult[$iRow][$iCol] != $sCell)
-				{
-					$iIssues++;
-					$sCellValue = "<span style =\"color: red; background-color: lightgrey;\">$sCellValue</span>, expecting '<span style =\"color: green; background-color: lightgrey;\">".$aExpectedResult[$iRow][$iCol]."</span>'";
-				}
-
-				echo "<td><pre>$sCellValue</pre></td>";
-			}
-			echo "</tr>\n";
-		}
-		echo "</table>\n";
-		return ($iIssues > 0);
-	}
-}
-
-class TestGenericItoMyModel extends TestBizModelGeneric
-{
-	static public function GetName()
-	{
-		return 'Generic RO test on '.self::GetConfigFile();
-	}
-
-	static public function GetConfigFile() {return '../config-test-mymodel.php';}
-}
-
-class TestGenericItopBigModel extends TestBizModelGeneric
-{
-	static public function GetName()
-	{
-		return 'Generic RO test on '.self::GetConfigFile();
-	}
-
-	static public function GetConfigFile() {return '../config-test-itopv06.php';}
-}
-
-class TestUserRightsMatrixItop extends TestUserRights
-{
-	static public function GetName()
-	{
-		return 'User rights test on user rights matrix';
-	}
-
-	static public function GetDescription()
-	{
-		return 'blah blah blah';
-	}
-
-	public function DoPrepare()
-	{
-		parent::DoPrepare();
-		MetaModel::Startup('../config-test-itopv06.php');
-	}
-
-	protected function DoExecute()
-	{
-		$sUser = 'Romain';
-		echo "<p>Totor: ".(UserRights::CheckCredentials('Totor', 'toto') ? 'ok' : 'NO')."</p>\n";
-		echo "<p>Romain: ".(UserRights::CheckCredentials('Romain', 'toto') ? 'ok' : 'NO')."</p>\n";
-		echo "<p>User: ".UserRights::GetUser()."</p>\n";
-		echo "<p>On behalf of...".UserRights::GetRealUser()."</p>\n";
-
-		echo "<p>Denis (impersonate) : ".(UserRights::Impersonate('Denis', 'tutu') ? 'ok' : 'NO')."</p>\n";
-		echo "<p>User: ".UserRights::GetUser()."</p>\n";
-		echo "<p>On behalf of...".UserRights::GetRealUser()."</p>\n";
-
-		$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT bizOrganization"));
-		echo "<p>IsActionAllowed...".(UserRights::IsActionAllowed('bizOrganization', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."</p>\n";
-		echo "<p>IsStimulusAllowed...".(UserRights::IsStimulusAllowed('bizOrganization', 'myStimulus', $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."</p>\n";
-		echo "<p>IsActionAllowedOnAttribute...".(UserRights::IsActionAllowedOnAttribute('bizOrganization', 'myattribute', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."</p>\n";
-		return true;
-	}
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Test a complex biz model on the fly
-///////////////////////////////////////////////////////////////////////////
-
-class TestMyBizModel extends TestBizModel
-{
-	static public function GetName()
-	{
-		return 'A series of tests on a weird business model';
-	}
-
-	static public function GetDescription()
-	{
-		return 'Attempts various operations and build complex queries';
-	}
-	
-	static public function GetConfigFile() {return '../config-test-mymodel.php';}
-
-	function test_linksinfo()
-	{
-		echo "<h4>Enum links</h4>";
-		self::DumpVariable(MetaModel::EnumReferencedClasses("cmdbTeam"));
-		self::DumpVariable(MetaModel::EnumReferencingClasses("Organization"));
-	
-		self::DumpVariable(MetaModel::EnumLinkingClasses());
-		self::DumpVariable(MetaModel::EnumLinkingClasses("cmdbContact"));
-		self::DumpVariable(MetaModel::EnumLinkingClasses("cmdWorkshop"));
-		self::DumpVariable(MetaModel::GetLinkLabel("Liens_entre_contacts_et_workshop", "toworkshop"));
-	}
-	
-	function test_list_attributes()
-	{
-		echo "<h4>List attributes</h4>";
-		foreach(MetaModel::ListAttributeDefs("cmdbTeam") as $sAttCode=>$oAttDef)
-		{
-			echo $oAttDef->GetLabel()." / ".$oAttDef->GetDescription()." / ".$oAttDef->GetType()."</br>\n";
-		}
-	}
-	
-	function test_search()
-	{
-		echo "<h4>Two searches</h4>";
-		$oFilterAllDevs = new DBObjectSearch("cmdbTeam");
-		$oAllDevs = new DBObjectSet($oFilterAllDevs);
-		
-		echo "Found ".$oAllDevs->Count()." items.</br>\n";
-		while ($oDev = $oAllDevs->Fetch())
-		{
-			$aValues = array();
-			foreach(MetaModel::GetAttributesList($oAllDevs->GetClass()) as $sAttCode)
-			{
-				$aValues[] = MetaModel::GetLabel(get_class($oDev), $sAttCode)." (".MetaModel::GetDescription(get_class($oDev), $sAttCode).") = ".$oDev->GetAsHTML($sAttCode);
-			}
-			echo $oDev->GetKey()." => ".implode(", ", $aValues)."</br>\n";
-		}
-	
-		// a second one
-		$oMyFilter = new DBObjectSearch("cmdbContact");
-		//$oMyFilter->AddCondition("name", "aii", "Finishes with");
-		$oMyFilter->AddCondition("name", "aii");
-		$this->search_and_show_list($oMyFilter);
-		
-	}
-	
-	function test_reload()
-	{
-		echo "<h4>Reload</h4>";
-		$team = MetaModel::GetObject("cmdbContact", "2");
-		echo "Chargement de l'attribut headcount: {$team->Get("headcount")}</br>\n";
-		self::DumpVariable($team);
-	}
-	
-	function test_setattribute()
-	{
-		echo "<h4>Set attribute and update</h4>";
-		$team = MetaModel::GetObject("cmdbTeam", "2");
-		$team->Set("headcount", rand(1,1000));
-		$team->Set("email", "Luis ".rand(9,250));
-		self::DumpVariable($team->ListChanges());
-		echo "New headcount = {$team->Get("headcount")}</br>\n";
-		echo "Computed name = {$team->Get("name")}</br>\n";
-	
-		$oMyChange = MetaModel::NewObject("CMDBChange");
-		$oMyChange->Set("date", time());
-		$oMyChange->Set("userinfo", "test_setattribute / Made by robot #".rand(1,100));
-		$iChangeId = $oMyChange->DBInsert();
-	
-		//MetaModel::StartDebugQuery();
-		$team->DBUpdateTracked($oMyChange);
-		//MetaModel::StopDebugQuery();
-	
-		echo "<h4>Check the modified team</h4>";
-		$oTeam = MetaModel::GetObject("cmdbTeam", "2");
-		self::DumpVariable($oTeam);
-	}
-	function test_newobject()
-	{
-		$oMyChange = MetaModel::NewObject("CMDBChange");
-		$oMyChange->Set("date", time());
-		$oMyChange->Set("userinfo", "test_newobject / Made by robot #".rand(1,100));
-		$iChangeId = $oMyChange->DBInsert();
-	
-		echo "<h4>Create a new object (team)</h4>";
-		$oNewTeam = MetaModel::NewObject("cmdbTeam");
-		$oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000));
-		$oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com");
-		$oNewTeam->Set("email", null);
-		$oNewTeam->Set("owner", "ITOP");
-		$oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value
-		$iId = $oNewTeam->DBInsertTracked($oMyChange);
-		echo "Created new team: $iId</br>";
-		echo "<h4>Delete team #$iId</h4>";
-		$oTeam = MetaModel::GetObject("cmdbTeam", $iId);
-		$oTeam->DBDeleteTracked($oMyChange);
-		echo "Deleted team: $iId</br>";
-		self::DumpVariable($oTeam);
-	}
-	
-	
-	function test_updatecolumn()
-	{
-		$oMyChange = MetaModel::NewObject("CMDBChange");
-		$oMyChange->Set("date", time());
-		$oMyChange->Set("userinfo", "test_updatecolumn / Made by robot #".rand(1,100));
-		$iChangeId = $oMyChange->DBInsert();
-	
-		$sNewEmail = "updatecol".rand(9,250)."@quedlaballe.com";
-		echo "<h4>Update a the email: set to '$sNewEmail'</h4>";
-		$oMyFilter = new DBObjectSearch("cmdbContact");
-		$oMyFilter->AddCondition("name", "o", "Contains");
-	
-		echo "Candidates before:</br>";
-		$this->search_and_show_list($oMyFilter);
-	
-		MetaModel::BulkUpdateTracked($oMyChange, $oMyFilter, array("email" => $sNewEmail));
-	
-		echo "Candidates after:</br>";
-		$this->search_and_show_list($oMyFilter);
-	}
-	
-	function test_error()
-	{
-		trigger_error("Stop requested", E_USER_ERROR);
-	}
-	
-	function test_changetracking()
-	{
-		echo "<h4>Create a change</h4>";
-		$oMyChange = MetaModel::NewObject("CMDBChange");
-		$oMyChange->Set("date", time());
-		$oMyChange->Set("userinfo", "Made by robot #".rand(1,100));
-		$iChangeId = $oMyChange->DBInsert();
-		echo "Created new change: $iChangeId</br>";
-		self::DumpVariable($oMyChange);
-	
-		echo "<h4>Create a new object (team)</h4>";
-		$oNewTeam = MetaModel::NewObject("cmdbTeam");
-		$oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000));
-		$oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com");
-		$oNewTeam->Set("email", null);
-		$oNewTeam->Set("owner", "ITOP");
-		$oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value
-		$iId = $oNewTeam->DBInsertTracked($oMyChange);
-		echo "Created new team: $iId</br>";
-		echo "<h4>Delete team #$iId</h4>";
-		$oTeam = MetaModel::GetObject("cmdbTeam", $iId);
-		$oTeam->DBDeleteTracked($oMyChange);
-		echo "Deleted team: $iId</br>";
-		self::DumpVariable($oTeam);
-	}
-	
-	function test_zlist()
-	{
-		echo "<h4>Test ZLists</h4>";
-		$aZLists = MetaModel::EnumZLists();
-		foreach ($aZLists as $sListCode)
-		{
-			$aListInfos = MetaModel::GetZListInfo($sListCode);
-			echo "<h4>List '".$sListCode."' (".$aListInfos["description"].") of type '".$aListInfos["type"]."'</h5>\n";
-	
-			foreach (MetaModel::GetSubclasses("cmdbObjectHomeMade") as $sKlass)
-			{
-				$aItems = MetaModel::GetZListItems($sKlass, $sListCode);
-				if (count($aItems) == 0) continue;
-	
-				echo "$sKlass - $sListCode : {".implode(", ", $aItems)."}</br>\n";
-			}
-		}
-	
-		echo "<h4>IsAttributeInZList()... </h4>";
-		echo "Liens_entre_contacts_et_workshop::ws_info in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "ws_info") ? "yes" : "no")."</br>\n";
-		echo "Liens_entre_contacts_et_workshop::toworkshop in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "toworkshop") ? "yes" : "no")."</br>\n";
-	
-	}
-	
-	function test_pkey()
-	{
-		echo "<h4>Test search on pkey</h4>";
-		$sExpr1 = "SELECT cmdbContact WHERE id IN (40, 42)";
-		$sExpr2 = "SELECT cmdbContact WHERE IN NOT IN (40, 42)";
-		$this->search_and_show_list_from_oql($sExpr1);
-		$this->search_and_show_list_from_oql($sExpr2);
-	
-		echo "Et maintenant, on fusionne....</br>\n";
-		$oSet1 = new CMDBObjectSet(DBObjectSearch::FromOQL($sExpr1));
-		$oSet2 = new CMDBObjectSet(DBObjectSearch::FromOQL($sExpr2));
-		$oIntersect = $oSet1->CreateIntersect($oSet2);
-		$oDelta = $oSet1->CreateDelta($oSet2);
-	
-		$oMerge = clone $oSet1;
-		$oMerge->Merge($oSet2);
-		$oMerge->Merge($oSet2);
-	
-		echo "Set1 - Found ".$oSet1->Count()." items.</br>\n";
-		echo "Set2 - Found ".$oSet2->Count()." items.</br>\n";
-		echo "Intersect - Found ".$oIntersect->Count()." items.</br>\n";
-		echo "Delta - Found ".$oDelta->Count()." items.</br>\n";
-		echo "Merge - Found ".$oMerge->Count()." items.</br>\n";
-		//$this->show_list($oObjSet);
-	}
-	
-	function test_relations()
-	{
-		echo "<h4>Test relations</h4>";
-		
-		//self::DumpVariable(MetaModel::EnumRelationQueries("cmdbObjectHomeMade", "Potes"));
-		self::DumpVariable(MetaModel::EnumRelationQueries("cmdbContact", "Potes"));
-	
-		$iMaxDepth = 9;
-		echo "Max depth = $iMaxDepth</br>\n";
-	
-		$oObj = MetaModel::GetObject("cmdbContact", 18);
-		$aRels = $oObj->GetRelatedObjects("Potes", $iMaxDepth);
-		echo $oObj->Get('name')." has some 'Potes'...</br>\n";
-		foreach ($aRels as $sClass => $aObjs)
-		{
-			echo "$sClass, count = ".count($aObjs)." =&gt; ".implode(', ', array_keys($aObjs))."</br>\n";
-			$oObjectSet = CMDBObjectSet::FromArray($sClass, $aObjs);
-			$this->show_list($oObjectSet);
-		}
-	
-		echo "<h4>Test relations - same results, by the mean of a OQL</h4>";
-		$this->search_and_show_list_from_oql("cmdbContact: RELATED (Potes, $iMaxDepth) TO (cmdbContact: pkey = 18)");
-		
-	}
-	
-	function test_linkedset()
-	{
-		echo "<h4>Linked set attributes</h4>\n";
-		$oObj = MetaModel::GetObject("cmdbContact", 18);
-		
-		echo "<h5>Current workshops</h5>\n";
-		$oSetWorkshopsCurr = $oObj->Get("myworkshops");
-		$this->show_list($oSetWorkshopsCurr);
-	
-		echo "<h5>Setting workshops</h5>\n";
-		$oNewLink = new cmdbLiens();
-		$oNewLink->Set('toworkshop', 2);
-		$oNewLink->Set('function', 'mafonctioooon');
-		$oNewLink->Set('a1', 'tralala1');
-		$oNewLink->Set('a2', 'F7M');
-		$oSetWorkshops = CMDBObjectSet::FromArray("cmdbLiens", array($oNewLink));
-		$oObj->Set("myworkshops", $oSetWorkshops); 
-		$this->show_list($oSetWorkshops);
-	
-		echo "<h5>New workshops</h5>\n";
-		$oSetWorkshopsCurr = $oObj->Get("myworkshops");
-		$this->show_list($oSetWorkshopsCurr);
-	
-		$oMyChange = MetaModel::NewObject("CMDBChange");
-		$oMyChange->Set("date", time());
-		$oMyChange->Set("userinfo", "test_linkedset / Made by robot #".rand(1,100));
-		$iChangeId = $oMyChange->DBInsert();
-		$oObj->DBUpdateTracked($oMyChange);
-		$oObj = MetaModel::GetObject("cmdbContact", 18);
-	
-		echo "<h5>After the write</h5>\n";
-		$oSetWorkshopsCurr = $oObj->Get("myworkshops");
-		$this->show_list($oSetWorkshopsCurr);
-	}
-	
-	function test_object_lifecycle()
-	{
-		echo "<h4>Test object lifecycle</h4>";
-	
-	
-		self::DumpVariable(MetaModel::GetStateAttributeCode("cmdbContact"));
-		self::DumpVariable(MetaModel::EnumStates("cmdbContact"));
-		self::DumpVariable(MetaModel::EnumStimuli("cmdbContact"));
-		foreach(MetaModel::EnumStates("cmdbContact") as $sStateCode => $aStateDef)
-		{
-			echo "<p>Transition from <strong>$sStateCode</strong></p>\n";
-			self::DumpVariable(MetaModel::EnumTransitions("cmdbContact", $sStateCode));
-		}
-	
-		$oObj = MetaModel::GetObject("cmdbContact", 18);
-		echo "Current state: ".$oObj->GetState()."... let's go to school...";
-		self::DumpVariable($oObj->EnumTransitions());
-		$oObj->ApplyStimulus("toschool");
-		echo "New state: ".$oObj->GetState()."... let's get older...";
-		self::DumpVariable($oObj->EnumTransitions());
-		$oObj->ApplyStimulus("raise");
-		echo "New state: ".$oObj->GetState()."... let's try to go further... (should give an error)";
-		self::DumpVariable($oObj->EnumTransitions());
-		$oObj->ApplyStimulus("raise"); // should give an error
-	}
-
-
-	protected function DoExecute()
-	{
-//				$this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
-//			$this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
-		//$this->test_linksinfo();
-		//$this->test_list_attributes();
-		//$this->test_search();
-		//$this->test_reload();
-		//$this->test_newobject();
-		$this->test_setattribute();
-		//$this->test_updatecolumn();
-		//$this->test_error();
-		//$this->test_changetracking();
-		$this->test_zlist();
-		$this->test_OQL();
-		//$this->test_pkey();
-		$this->test_relations();
-		$this->test_linkedset();
-		$this->test_object_lifecycle();
-	}
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// Test a complex biz model on the fly
-///////////////////////////////////////////////////////////////////////////
-
-abstract class MyFarm extends TestBizModel
-{
-	static public function GetConfigFile() {return '../config-test-farm.php';}
-
-	protected function DoPrepare()
-	{
-		parent::DoPrepare();
-		$this->ResetDB();
-		MetaModel::DBCheckIntegrity();
-	}
-
-	protected function InsertMammal($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $sName, $iHeight, $sBirth)
-	{
-		$oNew = MetaModel::NewObject('Mammal');
-		$oNew->Set('species', $sSpecies);
-		$oNew->Set('sex', $sSex);
-		$oNew->Set('speed', $iSpeed);
-		$oNew->Set('mother', $iMotherid);
-		$oNew->Set('father', $iFatherId);
-		$oNew->Set('name', $sName);
-		$oNew->Set('height', $iHeight);
-		$oNew->Set('birth', $sBirth);
-		return $this->ObjectToDB($oNew);
-	}
-
-	protected function InsertBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId)
-	{
-		$oNew = MetaModel::NewObject('Bird');
-		$oNew->Set('species', $sSpecies);
-		$oNew->Set('sex', $sSex);
-		$oNew->Set('speed', $iSpeed);
-		$oNew->Set('mother', $iMotherid);
-		$oNew->Set('father', $iFatherId);
-		return $this->ObjectToDB($oNew);
-	}
-
-	protected function InsertFlyingBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $iFlyingSpeed)
-	{
-		$oNew = MetaModel::NewObject('FlyingBird');
-		$oNew->Set('species', $sSpecies);
-		$oNew->Set('sex', $sSex);
-		$oNew->Set('speed', $iSpeed);
-		$oNew->Set('mother', $iMotherid);
-		$oNew->Set('father', $iFatherId);
-		$oNew->Set('flyingspeed', $iFlyingSpeed);
-		return $this->ObjectToDB($oNew);
-	}
-
-	private function InsertGroup($sName, $iLeaderId)
-	{
-		$oNew = MetaModel::NewObject('Group');
-		$oNew->Set('name', $sName);
-		$oNew->Set('leader', $iLeaderId);
-		$iId = $oNew->DBInsertNoReload();
-		return $iId;
-	}
-}
-
-
-class TestQueriesOnFarm extends MyFarm
-{
-	static public function GetName()
-	{
-		return 'Farm test';
-	}
-
-	static public function GetDescription()
-	{
-		return 'A series of tests on the farm business model (SQL generation)';
-	}
-
-	protected function CheckQuery($sQuery, $bIsCorrectQuery)
-	{
-		if ($bIsCorrectQuery)
-		{
-			echo "<h4 style=\"color:green;\">$sQuery</h4>\n";
-		}
-		else
-		{
-			echo "<h4 style=\"color:red;\">$sQuery</h3>\n";
-		}
-		try
-		{
-			//$oOql = new OqlInterpreter($sQuery);
-			//$oTrash = $oOql->ParseObjectQuery();
-			//self::DumpVariable($oTrash, true);
-			$oMyFilter = DBObjectSearch::FromOQL($sQuery);
-		}
-		catch (OQLException $oOqlException)
-		{
-			if ($bIsCorrectQuery)
-			{
-				echo "<p>More info on this unexpected failure:<br/>".$oOqlException->getHtmlDesc()."</p>\n";
-				throw $oOqlException;
-				return false;
-			}
-			else
-			{
-				// Everything is fine :-)
-				echo "<p>More info on this expected failure:\n";
-				echo "<ul>\n";
-				echo "<li>".get_class($oOqlException)."</li>\n";
-				echo "<li>".$oOqlException->getMessage()."</li>\n";
-				echo "<li>".$oOqlException->getHtmlDesc()."</li>\n";
-				echo "</ul>\n";
-				echo "</p>\n";
-				return true;
-			}
-		}
-		// The query was correctly parsed, was it expected to be correct ?
-		if (!$bIsCorrectQuery)
-		{
-			throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)");
-			return false;
-		}
-		echo "<p>To OQL: ".$oMyFilter->ToOQL()."</p>";
-
-		$this->search_and_show_list($oMyFilter);
-		
-		//echo "<p>first pass<p>\n";
-		//self::DumpVariable($oMyFilter, true);
-		$sQuery1 = MetaModel::MakeSelectQuery($oMyFilter);
-		//echo "<p>second pass<p>\n";
-		//self::DumpVariable($oMyFilter, true);
-		//$sQuery1 = MetaModel::MakeSelectQuery($oMyFilter);
-		
-		$sSerialize = $oMyFilter->serialize();
-		echo "<p>Serialized:$sSerialize</p>\n";
-		$oFilter2 = DBObjectSearch::unserialize($sSerialize);
-		try
-		{
-			$sQuery2 = MetaModel::MakeSelectQuery($oFilter2);
-		}
-		catch (Exception $e)
-		{
-			echo "<p>Could not compute the query after unserialize</p>\n";
-			echo "<p>Query 1: $sQuery1</p>\n";
-			MyHelpers::var_cmp_html($oMyFilter, $oFilter2);
-			throw $e;
-		}
-		//if ($oFilter2 != $oMyFilter) no, they may differ while the resulting query is the same!
-		if ($sQuery1 != $sQuery2)
-		{
-			echo "<p>serialize/unserialize mismatch :-(</p>\n";
-			MyHelpers::var_cmp_html($sQuery1, $sQuery2);
-			MyHelpers::var_cmp_html($oMyFilter, $oFilter2);
-			return false;
-		}
-		return true;
-	}
-
-	protected function DoExecute()
-	{
-//			$this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
-//			$this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
-		echo "<h3>Create protagonists...</h3>";
-
-		$iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19');
-		$iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23');
-		$this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23');
-		$this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01');
-		$this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11');
-
-		$this->InsertBird('rooster', 'male', 12, 0, 0);
-		$this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35);
-
-		// Benchmarking
-		//
-		if (false)
-		{
-			define ('COUNT_BENCHMARK', 10);
-			echo "<h3>Parsing a long query, ".COUNT_BENCHMARK." times</h3>";
-			$sQuery = "SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR) AND Dad.height * 2 <= ROUND(TO_DAYS(Dad.birth) / (3 + 1) * 5 - 3)";
-	
-			$fStart = MyHelpers::getmicrotime();
-			for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
-			{
-				$oMyFilter = DBObjectSearch::FromOQL($sQuery);
-			}
-			$fDuration = MyHelpers::getmicrotime() - $fStart;
-			$fParsingDuration = $fDuration / COUNT_BENCHMARK;
-			echo "<p>Mean time by op: $fParsingDuration</p>";
-		}
-
-		echo "<h3>Test queries...</h3>";
-
-		$aQueries = array(
-			'SELECT Animal' => true,
-			'SELECT Animal WHERE Animal.pkey = 1' => false,
-			'SELECT Animal WHERE Animal.id = 1' => true,
-			'SELECT Aniiimal' => false,
-			'SELECTe Animal' => false,
-			'SELECT * FROM Animal' => false,
-			'SELECT Animal AS zoo WHERE zoo.species = \'human\'' => true,
-			'SELECT Animal AS zoo WHERE species = \'human\'' => true,
-			'SELECT Animal AS zoo WHERE espece = \'human\'' => false,
-			'SELECT Animal AS zoo WHERE zoo.species IN (\'human\', "pig")' => true,
-			'SELECT Animal AS zoo WHERE CONCATENATION(zoo.species, zoo.sex) LIKE "hum%male"' => false,
-			'SELECT Animal AS zoo WHERE CONCAT(zoo.species, zoo.sex) LIKE "hum%male"' => true,
-			'SELECT Animal AS zoo WHERE zoo.species NOT IN (\'human\', "pig")' => true,
-			'SELECT Animal AS zoo WHERE zoo.kind = \'human\'' => false,
-			'SELECT Animal WHERE Animal.species = \'human\' AND Animal.sex = \'female\'' => true,
-			'SELECT Mammal AS x WHERE (x.species = \'human\' AND x.name LIKE \'ro%\') OR (x.species = \'donkey\' AND x.name LIKE \'po%\')' => true,
-			'SELECT Mammal AS x WHERE x.species = \'human\' AND x.name LIKE \'ro%\' OR x.species = \'donkey\' AND x.name LIKE \'po%\'' => true,
-			'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true,
-			'SELECT Mammal AS m WHERE DAY(m.birth) = 19' => true,
-			'SELECT Mammal AS m WHERE YEAR(m.birth) = 1971' => true,
-			'SELECT Mammal AS m WHERE m.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR)' => true,
-			'SELECT Mammal AS m WHERE m.birth > DATE_SUB(NOW(), INTERVAL 2000 DAY)' => true,
-			'SELECT Mammal AS m WHERE (TO_DAYS(NOW()) - TO_DAYS(m.birth)) > 2000' => true,
-			'SELECT Mammal AS m WHERE m.name = IF(FLOOR(ROUND(m.height)) > 2, "pomme", "romain")' => true,
-			'SELECT Mammal AS m WHERE (1 + 2' => false,
-			'SELECT Mammal AS m WHERE (1 + 2 * 4 / 23) > 0' => true,
-			'SELECT Mammal AS m WHERE (4 / 23 * 2 + 1) > 0' => true,
-			'SELECT Mammal AS m WHERE 1/0' => true,
-			'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true,
-			'SELECT Animal JOIN Group ON Group.leader = Animal.id' => true,
-			'SELECT Group JOIN Animal ON Group.leader = Animal.id' => true,
-			'SELECT Animal AS A JOIN Group AS G1 ON G1.leader = A.id' => true,
-			'SELECT Animal AS A JOIN Group AS G ON FooClass.leader = A.id' => false,
-			'SELECT Animal AS A JOIN Group AS G ON G.leader = FooClass.id' => false,
-			'SELECT Animal AS A JOIN Group AS G ON G.masterchief = A.id' => false,
-			'SELECT Animal AS A JOIN Group AS G ON A.id = G.leader' => false,
-			'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.qwerty = 123' => false,
-			'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.name LIKE "a%"' => true,
-			'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.id = 1' => true,
-			'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE id = 1' => false,
-			'SELECT Animal AS A JOIN Group AS G ON A.member = G.id' => false,
-			'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id' => true,
-			'SELECT Mammal AS M JOIN Group AS G ON A.member = G.id' => false,
-			'SELECT Mammal AS myAlias JOIN Group AS myAlias ON myAlias.member = myAlias.id' => false,
-			'SELECT Mammal AS Mammal JOIN Group AS Mammal ON Mammal.member = Mammal.id' => false,
-			'SELECT Group AS G WHERE G.leader_name LIKE "%"' => true,
-			'SELECT Group AS G WHERE G.leader_speed < 100000' => true,
-			'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true,
-			'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_speed < 100000' => true,
-			'SELECT Mammal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
-			'SELECT Mammal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true,
-			'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
-			'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true,
-			'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id' => true,
-			'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true,
-			'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.id = 1' => true,
-			'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\'' => false,
-			'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
-			'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\' OR Mum.speed = 0' => true,
-			'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true,
-			'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id' => true,
-			'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id JOIN Mammal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\' OR Mum.name=\'chloe\' OR Child.name=\'bizounours\'' => true,
-			// Specifying multiple objects
-			'SELECT Animal FROM Animal' => true,
-			'SELECT yelele FROM Animal' => false,
-			'SELECT Animal FROM Animal AS A' => false,
-			'SELECT A FROM Animal AS A' => true,
-		);
-		//$aQueries = array(
-		//	'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true,
-		//);
-		foreach($aQueries as $sQuery => $bIsCorrect)
-		{
-			$this->CheckQuery($sQuery, $bIsCorrect);
-		}
-		return true;
-	}
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// Test data load
-///////////////////////////////////////////////////////////////////////////
-
-class TestBulkChangeOnFarm extends TestBizModel
-{
-	static public function GetName()
-	{
-		return 'Farm test - data load';
-	}
-
-	static public function GetDescription()
-	{
-		return 'Bulk load';
-	}
-	
-	static public function GetConfigFile() {return '../config-test-farm.php';}
-
-	protected function DoPrepare()
-	{
-		parent::DoPrepare();
-		$this->ResetDB();
-		MetaModel::DBCheckIntegrity();
-	}
-
-	protected function DoExecute()
-	{
-//			$this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
-//			$this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
-
-		$oParser = new CSVParser("denomination,hauteur,age
-		suzy,123,2009-01-01
-		chita,456,
-		");
-		$aData = $oParser->ToArray(array('_name', '_height', '_birth'), ',');
-		self::DumpVariable($aData);
-
-		$oBulk = new BulkChange(
-			'Mammal',
-			$aData,
-			// attributes
-			array('name' => '_name', 'height' => '_height', 'birth' => '_birth'),
-			// ext keys
-			array(),
-			// reconciliation
-			array('name')
-		);
-
-		$oMyChange = MetaModel::NewObject("CMDBChange");
-		$oMyChange->Set("date", time());
-		$oMyChange->Set("userinfo", "Testor");
-		$iChangeId = $oMyChange->DBInsert();
-//		echo "Created new change: $iChangeId</br>";
-
-		echo "<h3>Planned for loading...</h3>";
-		$aRes = $oBulk->Process();
-		self::DumpVariable($aRes);
-		echo "<h3>Go for loading...</h3>";
-		$aRes = $oBulk->Process($oMyChange);
-		self::DumpVariable($aRes);
-
-		return;
-
-		$oRawData = array(
-			'Mammal',
-			array('species', 'sex', 'speed', 'mother', 'father', 'name', 'height', 'birth'),
-			"human,male,23,0,0,romulus,192,1971
-			human,male,23,0,0,remus,154,-50
-			human,male,23,0,0,julius,160,-49
-			human,female,23,0,0,cleopatra,142,-50
-			pig,female,23,0,0,confucius,50,2003"
-		);
-	}
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// Test data load
-///////////////////////////////////////////////////////////////////////////
-
-class TestFullTextSearchOnFarm extends MyFarm
-{
-	static public function GetName()
-	{
-		return 'Farm test - full text search';
-	}
-
-	static public function GetDescription()
-	{
-		return 'Focus on the full text search feature';
-	}
-	
-	protected function DoExecute()
-	{
-		echo "<h3>Create protagonists...</h3>";
-
-		$iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19');
-		$iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23');
-		$this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23');
-		$this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01');
-		$this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11');
-
-		$this->InsertBird('rooster', 'male', 12, 0, 0);
-		$this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35);
-
-		echo "<h3>Search...</h3>";
-		$oSearch = new DBObjectSearch('Mammal');
-		$oSearch->AddCondition_FullText('manof');
-		//$oResultSet = new DBObjectSet($oSearch);
-		$this->search_and_show_list($oSearch);
-	}
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// Benchmark queries
-///////////////////////////////////////////////////////////////////////////
-
-class TestItopEfficiency extends TestBizModel
-{
-	static public function GetName()
-	{
-		return 'Itop - benchmark';
-	}
-
-	static public function GetDescription()
-	{
-		return 'Measure time to perform the queries';
-	}
-
-	static public function GetConfigFile() {return '../config-itop.php';}
-
-	protected function DoBenchmark($sOqlQuery)
-	{
-		echo "<h3>Testing query: $sOqlQuery</h3>";
-
-		$fStart = MyHelpers::getmicrotime();
-		for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
-		{
-			$oFilter = DBObjectSearch::FromOQL($sOqlQuery);
-		}
-		$fDuration = MyHelpers::getmicrotime() - $fStart;
-		$fParsingDuration = $fDuration / COUNT_BENCHMARK;
-
-		$fStart = MyHelpers::getmicrotime();
-		for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
-		{
-			$sSQL = MetaModel::MakeSelectQuery($oFilter);
-		}
-		$fDuration = MyHelpers::getmicrotime() - $fStart;
-		$fBuildDuration = $fDuration / COUNT_BENCHMARK;
-
-		$fStart = MyHelpers::getmicrotime();
-		for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
-		{
-			$res = CMDBSource::Query($sSQL);
-		}
-		$fDuration = MyHelpers::getmicrotime() - $fStart;
-		$fQueryDuration = $fDuration / COUNT_BENCHMARK;
-
-		// The fetch could not be repeated with the same results
-		// But we've seen so far that is was very very quick to exec
-		// So it makes sense to benchmark it a single time
-		$fStart = MyHelpers::getmicrotime();
-		$aRow = CMDBSource::FetchArray($res);
-		$fDuration = MyHelpers::getmicrotime() - $fStart;
-		$fFetchDuration = $fDuration;
-
-		$fStart = MyHelpers::getmicrotime();
-		for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
-		{
-			$sOql = $oFilter->ToOQL();
-		}
-		$fDuration = MyHelpers::getmicrotime() - $fStart;
-		$fToOqlDuration = $fDuration / COUNT_BENCHMARK;
-
-		echo "<ul>\n";
-		echo "<li>Parsing: $fParsingDuration</li>\n";
-		echo "<li>Build: $fBuildDuration</li>\n";
-		echo "<li>Query: $fQueryDuration</li>\n";
-		echo "<li>Fetch: $fFetchDuration</li>\n";
-		echo "<li>ToOql: $fToOqlDuration</li>\n";
-		echo "</ul>\n";
-
-		// Everything but the ToOQL (wich is interesting, anyhow)
-		$fTotal = $fParsingDuration + $fBuildDuration + $fQueryDuration + $fFetchDuration; 
-
-		return array(
-			'rows' => CMDBSource::NbRows($res),
-			'duration (s)' => round($fTotal, 4),
-			'parsing (%)' => round(100 * $fParsingDuration / $fTotal, 1),
-			'build SQL (%)' => round(100 * $fBuildDuration / $fTotal, 1),
-			'query exec (%)' => round(100 * $fQueryDuration / $fTotal, 1),
-			'fetch (%)' => round(100 * $fFetchDuration / $fTotal, 1),
-			'to OQL (%)' => round(100 * $fToOqlDuration / $fTotal, 1),
-			'parsing+build (%)' => round(100 * ($fParsingDuration + $fBuildDuration) / $fTotal, 1),
-		);
-	}
-	
-	protected function DoExecute()
-	{
-		define ('COUNT_BENCHMARK', 3);
-		echo "<p>The test will be repeated ".COUNT_BENCHMARK." times</p>";
-
-		$aQueries = array(
-			'SELECT CMDBChangeOpSetAttribute',
-			'SELECT CMDBChangeOpSetAttribute WHERE id=10',
-			'SELECT CMDBChangeOpSetAttribute WHERE id=123456789',
-			'SELECT CMDBChangeOpSetAttribute WHERE CMDBChangeOpSetAttribute.id=10',
-			'SELECT Ticket',
-			'SELECT Ticket WHERE id=1',
-			'SELECT Person',
-			'SELECT Person WHERE id=1',
-			'SELECT Server',
-			'SELECT Server WHERE id=1',
-			'SELECT Incident JOIN Person ON Incident.agent_id = Person.id WHERE Person.id = 5',
-		);
-		$aStats  = array();
-		foreach ($aQueries as $sOQL)
-		{
-			$aStats[$sOQL] = $this->DoBenchmark($sOQL);
-		}
-
-		$aData = array();
-		foreach ($aStats as $sOQL => $aResults)
-		{
-			$aValues = array();
-			$aValues['OQL'] = htmlentities($sOQL);
-
-			foreach($aResults as $sDesc => $sInfo)
-			{
-				$aValues[$sDesc] = htmlentities($sInfo);
-			}
-			$aData[] = $aValues;
-		}
-		echo MyHelpers::make_table_from_assoc_array($aData);
-	}
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Test data load
-///////////////////////////////////////////////////////////////////////////
-
-class TestImportREST extends TestWebServices
-{
-	static public function GetName()
-	{
-		return 'CSV import (REST)';
-	}
-
-	static public function GetDescription()
-	{
-		return 'Test various options and fonctionality of import.php';
-	}
-
-	protected function DoExecSingleLoad($aLoadSpec)
-	{
-		$sCsvData = $aLoadSpec['csvdata'];
-
-		echo "<div style=\"padding: 10;\">\n";
-		echo "<h3 style=\"background-color: #ddddff; padding: 10;\">{$aLoadSpec['desc']}</h3>\n";
-
-		$aPostData = array('csvdata' => $sCsvData);
-
-		$aGetParams = array();
-		$aGetParamReport = array();
-		foreach($aLoadSpec['args'] as $sArg => $sValue)
-		{
-			$aGetParams[] = $sArg.'='.urlencode($sValue);
-			$aGetParamReport[] = $sArg.'='.$sValue;
-		}
-		$sGetParams = implode('&', $aGetParams);
-		$sLogin = isset($aLoadSpec['login']) ? $aLoadSpec['login'] : 'admin';
-		$sPassword = isset($aLoadSpec['password']) ? $aLoadSpec['password'] : 'admin';
-
-		$sRes = self::DoPostRequestAuth('../webservices/import.php?'.$sGetParams, $aPostData, $sLogin, $sPassword);
-
-		$sArguments = implode('<br/>', $aGetParamReport);
-
-		if (strlen($sCsvData) > 5000)
-		{
-			$sCsvDataViewable = 'INPUT TOO LONG TO BE DISPLAYED ('.strlen($sCsvData).")\n".substr($sCsvData, 0, 500)."\n... TO BE CONTINUED";
-		}
-		else
-		{
-			$sCsvDataViewable = $sCsvData;
-		}
-
-		echo "<div style=\"\">\n";
-		echo "   <div style=\"float:left; width:20%; padding:5; background-color:#eeeeff;\">\n";
-		echo "      $sArguments\n";
-		echo "   </div>\n";
-		echo "   <div style=\"float:right; width:75%; padding:5; background-color:#eeeeff\">\n";
-		echo "      <pre class=\"vardump\">$sCsvDataViewable</pre>\n";
-		echo "   </div>\n";
-		echo "</div>\n";
-
-		echo "<pre class=\"vardump\" style=\"clear: both; padding: 15; background-color: black; color: green;\">$sRes</pre>\n";
-
-		echo "</div>\n";
-	}
-	
-	protected function DoExecute()
-	{
-
-		$aLoads = array(
-			array(
-				'desc' => 'Missing class',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-				),
-				'csvdata' => "xxx",
-			),
-			array(
-				'desc' => 'Wrong class',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'toto',
-				),
-				'csvdata' => "xxx",
-			),
-			array(
-				'desc' => 'Wrong output type',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'NetworkDevice',
-					'output' => 'onthefly',
-				),
-				'csvdata' => "xxx",
-			),
-			array(
-				'desc' => 'Wrong report level',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'NetworkDevice',
-					'reportlevel' => 'errors|ouarnings|changed',
-				),
-				'csvdata' => "xxx",
-			),
-			array(
-				'desc' => 'Weird format, working anyhow...',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Server',
-					'output' => 'details',
-					'separator' => '*',
-					'qualifier' => '@',
-					'reconciliationkeys' => 'org_id,name',
-				),
-				'csvdata' => 'name*org_id
-									server01*2
-									  @server02@@combodo@*   2
-									server45*99',
-			),
-			array(
-				'desc' => 'Load an organization',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Organization',
-					'output' => 'details',
-					'reconciliationkeys' => '',
-				),
-				'csvdata' => "name;code\nWorldCompany;WCY",
-			),
-			array(
-				'desc' => 'Load a location',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-					'reconciliationkeys' => '',
-				),
-				'csvdata' => "name;org_id;address\nParis;1;Centre de la Franca",
-			),
-			array(
-				'desc' => 'Load a person',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Person',
-					'output' => 'details',
-					'reconciliationkeys' => '',
-				),
-				'csvdata' => "email;name;first_name;org_id;phone\njohn.foo@starac.com;Foo;John;1;+33(1)23456789",
-			),
-			array(
-				'desc' => 'Load a person - wrong email format',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Person',
-					'output' => 'details',
-					'reconciliationkeys' => '',
-				),
-				'csvdata' => "email;name;first_name;org_id\nemailPASbon;Foo;John;1",
-			),
-			array(
-				'desc' => 'Load a team',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Team',
-					'output' => 'details',
-					'reconciliationkeys' => '',
-				),
-				'csvdata' => "name;org_id;location_name\nSquadra Azzura2;1;Paris",
-			),
-			array(
-				'desc' => 'Load server',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Server',
-					'output' => 'details',
-					'reconciliationkeys' => '',
-				),
-				'csvdata' => "name;status;owner_name;location_name;location_id->org_name;os_family;os_version;management_ip;cpu;ram;brand;model;serial_number\nlocalhost.;production;Demo;Grenoble;Demo;Ubuntu 9.10;2.6.31-19-generic-#56-Ubuntu SMP Thu Jan 28 01:26:53 UTC 2010;16.16.230.232;Intel(R) Core(TM)2 Duo CPU     T7100  @ 1.80GHz;2005;Hewlett-Packard;HP Compaq 6510b (GM108UC#ABF);CNU7370BNP",
-			),
-			array(
-				'desc' => 'Load NW if',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'NetworkInterface',
-					'output' => 'details',
-					'reconciliationkeys' => '',
-				),
-				'csvdata' => "name;status;org_id;device_name;physical_type;ip_address;ip_mask;mac_address;speed\neth0;implementation;2;localhost.;ethernet;16.16.230.232;255.255.240.0;00:1a:4b:68:e3:97;\nlo;implementation;2;localhost.;ethernet;127.0.0.1;255.0.0.0;;",
-			),
-			// Data Bruno
-			array(
-				'desc' => 'Load NW devices from real life',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'NetworkDevice',
-					'output' => 'details',
-					'reconciliationkeys' => 'org_id->name,name',
-					),
-				'csvdata' => 'name;management_ip;importance;org_id->name;type
-									truc-machin-bidule;172.15.255.150;high;My Company/Department;switch
-									10.15.255.222;10.15.255.222;high;My Company/Department;switch',
-			),
-			array(
-				'desc' => 'Load NW ifs',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'NetworkInterface',
-					'output' => 'details',
-					'reconciliationkeys' => 'device_id->name,name',
-				),
-				'csvdata' => 'device_id->name;org_id->name;name;ip_address;ip_mask;speed;link_type;mac_address;physical_type
-					truc-machin-bidule;My Company/Department;"GigabitEthernet44";;;0;downlink;00 12 F2 CB C4 EB ;ethernet
-					truc-machin-bidule;My Company/Department;"GigabitEthernet38";;;0;downlink;00 12 F2 CB C4 E5 ;ethernet
-					un-autre;My Company/Department;"GigabitEthernet2/3";;;1000000000;uplink;00 12 F2 20 0F 1A ;ethernet',
-			),
-			array(
-				'desc' => 'The simplest data load',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-				),
-				'csvdata' => "name\nParis",
-			),
-			array(
-				'desc' => 'The simplest data load + org',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-				),
-				'csvdata' => "name;org_id\nParis;2",
-			),
-			array(
-				'desc' => 'The simplest data load + org (name)',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-				),
-				'csvdata' => "name;org_name\nParis;Demo",
-			),
-			array(
-				'desc' => 'The simplest data load + org (code)',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-				),
-				'csvdata' => "name;org_id->code\nParis;DEMO",
-			),
-			array(
-				'desc' => 'Ouput: summary',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'summary',
-				),
-				'csvdata' => "name;org_id->code\nParis;DEMO",
-			),
-			array(
-				'desc' => 'Ouput: retcode',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'retcode',
-				),
-				'csvdata' => "name;org_id->code\nParis;DEMO",
-			),
-			array(
-				'desc' => 'Error in reconciliation list',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-					'reconciliationkeys' => 'org_id',
-				),
-				'csvdata' => "org_name;name\nDemo;Paris",
-			),
-			array(
-				'desc' => 'Error in attribute list that does not allow to compute reconciliation scheme',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-				),
-				'csvdata' => "org_name;country\nDemo;France",
-			),
-			array(
-				'desc' => 'Error in attribute list - case A',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-				),
-				'csvdata' => "name;org\nParis;2",
-			),
-			array(
-				'desc' => 'Error in attribute list - case B1 (key->attcode)',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-				),
-				'csvdata' => "name;org->code\nParis;DEMO",
-			),
-			array(
-				'desc' => 'Error in attribute list - case B2 (key->attcode)',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-				),
-				'csvdata' => "name;org_id->duns\nParis;DEMO",
-			),
-			array(
-				'desc' => 'Always changing... special comment in change tracking',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-					'comment' => 'automated testing'
-				),
-				'csvdata' => "org_name;name;address\nDemo;Le pantheon;Addresse bidon:".((string)microtime(true)),
-			),
-			array(
-				'desc' => 'Always changing... but "simulate"',
-				'login' => 'admin',
-				'password' => 'admin',
-				'args' => array(
-					'class' => 'Location',
-					'output' => 'details',
-					'simulate' => '1',
-					'comment' => 'SHOULD NEVER APPEAR IN THE HISTORY'
-				),
-				'csvdata' => "org_name;name;address\nDemo;Le pantheon;restore address?",
-			),
-		); 
-
-		foreach ($aLoads as $aLoadSpec)
-		{
-			$this->DoExecSingleLoad($aLoadSpec);
-		}
-	}
-}
-
-///////////////////////////////////////////////////////////////////////////
-// Test massive data load
-///////////////////////////////////////////////////////////////////////////
-define('IMPORT_COUNT', 1000);
-
-class TestImportRESTMassive extends TestImportREST
-{
-	static public function GetName()
-	{
-		return 'CSV import (REST) - HUGE data set ('.IMPORT_COUNT.' PCs)';
-	}
-
-	static public function GetDescription()
-	{
-		return 'Stress import.php';
-	}
-
-	protected function DoExecute()
-	{
-		$aLoadSpec = array(
-			'desc' => 'Missing class',
-			'args' => array(
-				'class' => 'PC',
-				'output' => 'summary',
-			),
-			'csvdata' => "name;org_id;brand\n",
-		);
-		for($i = 0 ; $i <= IMPORT_COUNT ; $i++)
-		{
-			$aLoadSpec['csvdata'] .= "pc.import.$i;2;Combodo\n";
-		}
-		$this->DoExecSingleLoad($aLoadSpec);
-	}
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-// Test SOAP services
-///////////////////////////////////////////////////////////////////////////
-
-$aWebServices = array(
-	array(
-		'verb' => 'GetVersion',
-		'expected result' => WebServices::GetVersion(),
-		'explain result' => 'no comment!',
-		'args' => array(),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => true,
-		'explain result' => 'link attribute unknown + a CI not found',
-		'args' => array(
-			'admin', /* sLogin */
-			'admin', /* sPassword */
-			'desc of ticket', /* sDescription */
-			'initial situation blah blah blah', /* sInitialSituation */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			array(
-				new SOAPLinkCreationSpec(
-					'InfrastructureCI',
-					array(new SOAPSearchCondition('name', 'dbserver1.demo.com')),
-					array(new SOAPAttributeValue('impacting', 'very critical'))
-				),
-				new SOAPLinkCreationSpec(
-					'NetworkDevice',
-					array(new SOAPSearchCondition('name', 'switch01')),
-					array(new SOAPAttributeValue('impact', 'who cares'))
-				),
-				new SOAPLinkCreationSpec(
-					'Server',
-					array(new SOAPSearchCondition('name', 'thisone')),
-					array(new SOAPAttributeValue('impact', 'our lives'))
-				),
-			), /* aImpact */
-			'1', /* sImpact */
-			'1', /* sUrgency */
-		),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => true,
-		'explain result' => 'caller not specified',
-		'args' => array(
-			'admin', /* sLogin */
-			'admin', /* sPassword */
-			'PC burning', /* sDescription */
-			'The power supply suddenly started to warm up', /* sInitialSituation */
-			new SOAPExternalKeySearch(), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			array(
-				new SOAPLinkCreationSpec(
-					'InfrastructureCI',
-					array(new SOAPSearchCondition('name', 'dbserver1.demo.com')),
-					array()
-				), /* aImpact */
-			),
-			'1', /* sImpact */
-			'1', /* sUrgency */
-		),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => false,
-		'explain result' => 'wrong class on CI to attach',
-		'args' => array(
-			'admin', /* sLogin */
-			'admin', /* sPassword */
-			'PC burning', /* sDescription */
-			'The power supply suddenly started to warm up', /* sInitialSituation */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			array(
-				new SOAPLinkCreationSpec(
-					'logInfra',
-					array(new SOAPSearchCondition('dummyfiltercode', 2)),
-					array(new SOAPAttributeValue('impact', 'very critical'))
-				),
-			), /* aImpact */
-			'1', /* sImpact */
-			'1', /* sUrgency */
-		),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => false,
-		'explain result' => 'wrong search condition on CI to attach',
-		'args' => array(
-			'admin', /* sLogin */
-			'admin', /* sPassword */
-			'PC burning', /* sDescription */
-			'The power supply suddenly started to warm up', /* sInitialSituation */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			array(
-				new SOAPLinkCreationSpec(
-					'InfrastructureCI',
-					array(new SOAPSearchCondition('dummyfiltercode', 2)),
-					array(new SOAPAttributeValue('impact', 'very critical'))
-				),
-			), /* aImpact */
-			'1', /* sImpact */
-			'1', /* sUrgency */
-		),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => true,
-		'explain result' => 'no CI to attach (empty array)',
-		'args' => array(
-			'admin', /* sLogin */
-			'admin', /* sPassword */
-			'Houston not reachable', /* sDescription */
-			'Tried to join the shuttle', /* sInitialSituation */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			array(
-			), /* aImpact */
-			'1', /* sImpact */
-			'1', /* sUrgency */
-		),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => true,
-		'explain result' => 'no CI to attach (null)',
-		'args' => array(
-			'admin', /* sLogin */
-			'admin', /* sPassword */
-			'Houston not reachable', /* sDescription */
-			'Tried to join the shuttle', /* sInitialSituation */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			null,  /* aImpact */
-			'1', /* sImpact */
-			'1', /* sUrgency */
-		),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => true,
-		'explain result' => 'caller unknown',
-		'args' => array(
-			'admin', /* sLogin */
-			'admin', /* sPassword */
-			'Houston not reachable', /* sDescription */
-			'Tried to join the shuttle', /* sInitialSituation */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1000))), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			array(
-			), /* aImpact */
-			'1', /* sImpact */
-			'1', /* sUrgency */
-		),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => false,
-		'explain result' => 'wrong values for impact and urgency',
-		'args' => array(
-			'admin', /* sLogin */
-			'admin', /* sPassword */
-			'Houston not reachable', /* sDescription */
-			'Tried to join the shuttle', /* sInitialSituation */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			array(
-			), /* aImpact */
-			'6', /* sImpact */
-			'7', /* sUrgency */
-		),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => false,
-		'explain result' => 'wrong password',
-		'args' => array(
-			'admin', /* sLogin */
-			'xxxxx', /* sPassword */
-			'Houston not reachable', /* sDescription */
-			'Tried to join the shuttle', /* sInitialSituation */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			array(
-			), /* aImpact */
-			'1', /* sImpact */
-			'1', /* sUrgency */
-		),
-	),
-	array(
-		'verb' => 'CreateIncidentTicket',
-		'expected result' => false,
-		'explain result' => 'wrong login',
-		'args' => array(
-			'xxxxx', /* sLogin */
-			'yyyyy', /* sPassword */
-			'Houston not reachable', /* sDescription */
-			'Tried to join the shuttle', /* sInitialSituation */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aCallerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Demo'))), /* aCustomerDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'HW Management'))), /* aServiceDesc */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('id', 1))), /* aServiceSubcategoryDesc */
-			'sub product of the service', /* sProduct */
-			new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', 'Hardware support'))), /* aWorkgroupDesc */
-			array(
-			), /* aImpact */
-			'1', /* sImpact */
-			'1', /* sUrgency */
-		),
-	),
-);
-
-
-class TestSoap extends TestSoapWebService
-{
-	static public function GetName() {return 'Test SOAP';}
-	static public function GetDescription() {return 'Do basic stuff to test the SOAP capability';}
-
-	protected function DoExecute()
-	{
-		echo "<p>Note: You may also want to try the sample SOAP client <a href=\"../webservices/itopsoap.examples.php\">itopsoap.examples.php</a></p>\n";
-
-		global $aSOAPMapping;
-
-		// this file is generated dynamically with location = here
-		$sWsdlUri = 'http'.(empty($_SERVER['HTTPS']) ? '' : 's').'://'.$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].dirname($_SERVER['SCRIPT_NAME']).'/../webservices/itop.wsdl.php';
-
-		ini_set("soap.wsdl_cache_enabled","0");
-		$this->m_SoapClient = new SoapClient
-		(
-			$sWsdlUri,
-			array(
-				'classmap' => $aSOAPMapping,
-				'trace' => 1,
-			)
-		);
-
-		if (false)
-		{
-			self::DumpVariable($this->m_SoapClient->__getTypes());
-		} 
-
-		global $aWebServices;
-		foreach ($aWebServices as $iPos => $aWebService)
-		{
-			echo "<h2>SOAP call #$iPos - {$aWebService['verb']}</h2>\n";
-			echo "<p>{$aWebService['explain result']}</p>\n";
-
-			try
-			{
-				$oRes = call_user_func_array(array($this->m_SoapClient, $aWebService['verb']), $aWebService['args']);
-			}
-			catch(SoapFault $e)
-			{
-				print "<pre>\n"; 
-				print "Request: \n".htmlspecialchars($this->m_SoapClient->__getLastRequest()) ."\n"; 
-				print "Response: \n".htmlspecialchars($this->m_SoapClient->__getLastResponse())."\n"; 
-				print "</pre>";
-				print "Response in HTML: <p>".$this->m_SoapClient->__getLastResponse()."</p>"; 
-				throw $e;
-			}
-
-			self::DumpVariable($oRes);
-	
-			print "<pre>\n"; 
-			print "Request: \n".htmlspecialchars($this->m_SoapClient->__getLastRequest()) ."\n"; 
-			print "Response: \n".htmlspecialchars($this->m_SoapClient->__getLastResponse())."\n"; 
-			print "</pre>";
-
-			if ($oRes instanceof SOAPResult)
-			{
-				$res = $oRes->status;
-			}
-			else
-			{
-				$res = $oRes;
-			}
-			if ($res != $aWebService['expected result'])
-			{
-				echo "Expecting:<br/>\n";
-				var_dump($aWebService['expected result']);
-				echo "Obtained:<br/>\n";
-				var_dump($res);
-				throw new UnitTestException("Expecting result '{$aWebService['expected result']}', but got '$res'");
-			}
-		} 
-	}
-}
-
-class TestWebServicesDirect extends TestBizModel
-{
-	static public function GetName() {return 'Test web services locally';}
-	static public function GetDescription() {return 'Invoke the service directly (troubleshooting)';}
-
-	static public function GetConfigFile() {return '../config-itop.php';}
-
-	protected function DoExecute()
-	{
-		$oWebServices = new WebServices();
-
-		global $aWebServices;
-		foreach ($aWebServices as $iPos => $aWebService)
-		{
-			echo "<h2>SOAP call #$iPos - {$aWebService['verb']}</h2>\n";
-			echo "<p>{$aWebService['explain result']}</p>\n";
-			$oRes = call_user_func_array(array($oWebServices, $aWebService['verb']), $aWebService['args']);
-			self::DumpVariable($oRes);
-
-			if ($oRes instanceof SOAPResult)
-			{
-				$res = $oRes->status;
-			}
-			else
-			{
-				$res = $oRes;
-			}
-			if ($res != $aWebService['expected result'])
-			{
-				echo "Expecting:<br/>\n";
-				var_dump($aWebService['expected result']);
-				echo "Obtained:<br/>\n";
-				var_dump($res);
-				throw new UnitTestException("Expecting result '{$aWebService['expected result']}', but got '$res'");
-			}
-		}
-		return true;
-	}
-}
-
-class TestTriggerAndEmail extends TestBizModel
-{
-	static public function GetName() {return 'Test trigger and email';}
-	static public function GetDescription() {return 'Create a trigger and an email, then activates the trigger';}
-
-	static public function GetConfigFile() {return '../config-itop.php';}
-
-	protected function CreateEmailSpec($oTrigger, $sStatus, $sTo, $sCC, $sTesterEmail)
-	{
-		$oAction = MetaModel::NewObject("ActionEmail");
-		$oAction->Set("status", $sStatus);
-		$oAction->Set("name", "New server");
-		$oAction->Set("test_recipient", $sTesterEmail);
-		$oAction->Set("from", $sTesterEmail);
-		$oAction->Set("reply_to", $sTesterEmail);
-		$oAction->Set("to", $sTo);
-		$oAction->Set("cc", $sCC);
-		$oAction->Set("bcc", "");
-		$oAction->Set("subject", "New server: '\$this->name()$'");
-		$oAction->Set("body", "<html><body><p>Dear customer,</p><p>We have created the server \$this->hyperlink()$ in the IT infrastructure database.</p><p>You will be further notified when it is in <strong>Production</strong>.</p><p>The IT infrastructure management team.</p><p>Here are some accentuated characters for french people: 'ééà'</p></body></html>");
-		$oAction->Set("importance", "low");
-		$iActionId = $this->ObjectToDB($oAction, true);
-
-		$oLink = MetaModel::NewObject("lnkTriggerAction");
-		$oLink->Set("trigger_id", $oTrigger->GetKey());
-		$oLink->Set("action_id", $iActionId);
-		$oLink->Set("order", "1");
-		$iLink = $this->ObjectToDB($oLink, true);
-	}
-
-	protected function DoExecute()
-	{
-		$oMyPerson = MetaModel::NewObject("bizPerson");
-		$oMyPerson->Set("name", "testemail1");
-		$oMyPerson->Set("org_id", "1");
-		$oMyPerson->Set("email", "romain.quetiez@hp.com");
-		$iPersonId = $this->ObjectToDB($oMyPerson, true);
-
-		$oMyPerson = MetaModel::NewObject("bizPerson");
-		$oMyPerson->Set("name", "testemail2");
-		$oMyPerson->Set("org_id", "1");
-		$oMyPerson->Set("email", "denis.flaven@hp.com");
-		$iPersonId = $this->ObjectToDB($oMyPerson, true);
-
-		$oMyPerson = MetaModel::NewObject("bizPerson");
-		$oMyPerson->Set("name", "testemail3");
-		$oMyPerson->Set("org_id", "1");
-		$oMyPerson->Set("email", "erwan.taloc@hp.com");
-		$iPersonId = $this->ObjectToDB($oMyPerson, true);
-
-		$oMyServer = MetaModel::NewObject("bizServer");
-		$oMyServer->Set("name", "wfr.terminator.com");
-		$oMyServer->Set("severity", "low");
-		$oMyServer->Set("status", "production");
-		$oMyServer->Set("org_id", 2);
-		$oMyServer->Set("location_id", 2);
-		$iServerId = $this->ObjectToDB($oMyServer, true);
-
-		$oMyTrigger = MetaModel::NewObject("TriggerOnStateEnter");
-		$oMyTrigger->Set("description", "Testor");
-		$oMyTrigger->Set("target_class", "bizServer");
-		$oMyTrigger->Set("state", "Shipped");
-		$iTriggerId = $this->ObjectToDB($oMyTrigger, true);
-
-		// Error in OQL field(s)
-		//
-		$this->CreateEmailSpec
-		(
-			$oMyTrigger,
-			'test',
-			"SELECT bizPerson WHERE naime = 'Dali'",
-			"SELECT bizServer",
-			'romain.quetiez@hp.com'
-		);
-
-		// Error: no recipient
-		//
-		$this->CreateEmailSpec
-		(
-			$oMyTrigger,
-			'test',
-			"",
-			"",
-			'romain.quetiez@hp.com'
-		);
-
-		// Test
-		//
-		$this->CreateEmailSpec
-		(
-			$oMyTrigger,
-			'test',
-			"SELECT bizPerson WHERE name LIKE 'testemail%'",
-			"SELECT bizPerson",
-			'romain.quetiez@hp.com'
-		);
-
-		// Test failing because of a wrong test recipient address
-		//
-		$this->CreateEmailSpec
-		(
-			$oMyTrigger,
-			'test',
-			"SELECT bizPerson WHERE name LIKE 'testemail%'",
-			"",
-			'toto@walibi.bg'
-		);
-
-		// Normal behavior
-		//
-		$this->CreateEmailSpec
-		(
-			$oMyTrigger,
-			'enabled',
-			"SELECT bizPerson WHERE name LIKE 'testemail%'",
-			"",
-			'romain.quetiez@hp.com'
-		);
-
-		// Does nothing, because it is disabled
-		//
-		$this->CreateEmailSpec
-		(
-			$oMyTrigger,
-			'disabled',
-			"SELECT bizPerson WHERE name = 'testemail%'",
-			"",
-			'romain.quetiez@hp.com'
-		);
-
-		$oMyTrigger->DoActivate($oMyServer->ToArgs('this'));
-
-		return true;
-	}
-}
-?>