test.class.inc.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. <?php
  2. require_once('coreexception.class.inc.php');
  3. require_once('attributedef.class.inc.php');
  4. require_once('filterdef.class.inc.php');
  5. require_once('stimulus.class.inc.php');
  6. require_once('MyHelpers.class.inc.php');
  7. require_once('expression.class.inc.php');
  8. require_once('cmdbsource.class.inc.php');
  9. require_once('sqlquery.class.inc.php');
  10. require_once('dbobject.class.php');
  11. require_once('dbobjectsearch.class.php');
  12. require_once('dbobjectset.class.php');
  13. require_once('userrights.class.inc.php');
  14. // Just to differentiate programmatically triggered exceptions and other kind of errors (usefull?)
  15. class UnitTestException extends Exception
  16. {}
  17. /**
  18. * Improved display of the backtrace
  19. *
  20. * @package iTopORM
  21. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  22. * @author Denis Flaven <denisflave@free.fr>
  23. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  24. * @link www.itop.com
  25. * @since 1.0
  26. * @version 1.1.1.1 $
  27. */
  28. class ExceptionFromError extends Exception
  29. {
  30. public function getTraceAsHtml()
  31. {
  32. $aBackTrace = $this->getTrace();
  33. return MyHelpers::get_callstack_html(0, $this->getTrace());
  34. // return "<pre>\n".$this->getTraceAsString()."</pre>\n";
  35. }
  36. }
  37. /**
  38. * Test handler API and basic helpers
  39. *
  40. * @package iTopORM
  41. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  42. * @author Denis Flaven <denisflave@free.fr>
  43. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  44. * @link www.itop.com
  45. * @since 1.0
  46. * @version 1.1.1.1 $
  47. */
  48. abstract class TestHandler
  49. {
  50. protected $m_aSuccesses;
  51. protected $m_aWarnings;
  52. protected $m_aErrors;
  53. protected $m_sOutput;
  54. public function __construct()
  55. {
  56. $this->m_aSuccesses = array();
  57. $this->m_aWarnings = array();
  58. $this->m_aErrors = array();
  59. }
  60. abstract static public function GetName();
  61. abstract static public function GetDescription();
  62. protected function DoPrepare() {return true;}
  63. abstract protected function DoExecute();
  64. protected function DoCleanup() {return true;}
  65. protected function ReportSuccess($sMessage, $sSubtestId = '')
  66. {
  67. $this->m_aSuccesses[] = $sMessage;
  68. }
  69. protected function ReportWarning($sMessage, $sSubtestId = '')
  70. {
  71. $this->m_aWarnings[] = $sMessage;
  72. }
  73. protected function ReportError($sMessage, $sSubtestId = '')
  74. {
  75. $this->m_aErrors[] = $sMessage;
  76. }
  77. public function GetResults()
  78. {
  79. return $this->m_aSuccesses;
  80. }
  81. public function GetWarnings()
  82. {
  83. return $this->m_aWarnings;
  84. }
  85. public function GetErrors()
  86. {
  87. return $this->m_aErrors;
  88. }
  89. public function GetOutput()
  90. {
  91. return $this->m_sOutput;
  92. }
  93. public function error_handler($errno, $errstr, $errfile, $errline)
  94. {
  95. // Note: return false to call the default handler (stop the program if an error)
  96. switch ($errno)
  97. {
  98. case E_USER_ERROR:
  99. $this->ReportError($errstr);
  100. //throw new ExceptionFromError("Fatal error in line $errline of file $errfile: $errstr");
  101. break;
  102. case E_USER_WARNING:
  103. $this->ReportWarning($errstr);
  104. break;
  105. case E_USER_NOTICE:
  106. $this->ReportWarning($errstr);
  107. break;
  108. default:
  109. throw new ExceptionFromError("Fatal warning in line $errline of file $errfile: $errstr");
  110. $this->ReportWarning("Unknown error type: [$errno] $errstr");
  111. echo "Unknown error type: [$errno] $errstr<br />\n";
  112. break;
  113. }
  114. return true; // do not call the default handler
  115. }
  116. public function Execute()
  117. {
  118. ob_start();
  119. set_error_handler(array($this, 'error_handler'));
  120. try
  121. {
  122. $this->DoPrepare();
  123. $this->DoExecute();
  124. }
  125. catch (ExceptionFromError $e)
  126. {
  127. $this->ReportError($e->getMessage().' - '.$e->getTraceAsHtml());
  128. }
  129. catch (CoreException $e)
  130. {
  131. //$this->ReportError($e->getMessage());
  132. //$this->ReportError($e->__tostring());
  133. $this->ReportError($e->getMessage().' - '.$e->getTraceAsHtml());
  134. }
  135. catch (Exception $e)
  136. {
  137. //$this->ReportError($e->getMessage());
  138. //$this->ReportError($e->__tostring());
  139. $this->ReportError('class '.get_class($e).' --- '.$e->getMessage().' - '.$e->getTraceAsString());
  140. }
  141. restore_error_handler();
  142. $this->m_sOutput = ob_get_clean();
  143. return (count($this->GetErrors()) == 0);
  144. }
  145. }
  146. /**
  147. * Test to execute a piece of code (checks if an error occurs)
  148. *
  149. * @package iTopORM
  150. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  151. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  152. * @link www.itop.com
  153. * @since 1.0
  154. * @version $itopversion$
  155. */
  156. abstract class TestFunction extends TestHandler
  157. {
  158. // simply overload DoExecute (temporary)
  159. }
  160. /**
  161. * Test to execute a piece of code (checks if an error occurs)
  162. *
  163. * @package iTopORM
  164. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  165. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  166. * @link www.itop.com
  167. * @since 1.0
  168. * @version $itopversion$
  169. */
  170. abstract class TestWebServices extends TestHandler
  171. {
  172. // simply overload DoExecute (temporary)
  173. static protected function DoPostRequestAuth($sRelativeUrl, $aData, $sLogin = 'admin', $sPassword = '', $sOptionnalHeaders = null)
  174. {
  175. $aDataAndAuth = $aData;
  176. $aDataAndAuth['operation'] = 'login';
  177. $aDataAndAuth['auth_user'] = $sLogin;
  178. $aDataAndAuth['auth_pwd'] = $sPassword;
  179. $sHost = $GLOBALS['_SERVER']['HTTP_HOST'];
  180. $sUrl = "http://$sHost/$sRelativeUrl";
  181. return self::DoPostRequest($sUrl, $aDataAndAuth, $sOptionnalHeaders);
  182. }
  183. // Source: http://netevil.org/blog/2006/nov/http-post-from-php-without-curl
  184. // originaly named after do_post_request
  185. // Partially adapted to our coding conventions
  186. static protected function DoPostRequest($sUrl, $aData, $sOptionnalHeaders = null)
  187. {
  188. // $sOptionnalHeaders is a string containing additional HTTP headers that you would like to send in your request.
  189. $sData = http_build_query($aData);
  190. $aParams = array('http' => array(
  191. 'method' => 'POST',
  192. 'content' => $sData,
  193. 'header'=> "Content-type: application/x-www-form-urlencoded\r\nContent-Length: ".strlen($sData)."\r\n",
  194. ));
  195. if ($sOptionnalHeaders !== null)
  196. {
  197. $aParams['http']['header'] .= $sOptionnalHeaders;
  198. }
  199. $ctx = stream_context_create($aParams);
  200. $fp = @fopen($sUrl, 'rb', false, $ctx);
  201. if (!$fp)
  202. {
  203. throw new Exception("Problem with $sUrl, $php_errormsg");
  204. }
  205. $response = @stream_get_contents($fp);
  206. if ($response === false)
  207. {
  208. throw new Exception("Problem reading data from $sUrl, $php_errormsg");
  209. }
  210. return $response;
  211. }
  212. }
  213. /**
  214. * Test to check that a function outputs some values depending on its input
  215. *
  216. * @package iTopORM
  217. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  218. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  219. * @link www.itop.com
  220. * @since 1.0
  221. * @version $itopversion$
  222. */
  223. abstract class TestFunctionInOut extends TestFunction
  224. {
  225. abstract static public function GetCallSpec(); // parameters to call_user_func
  226. abstract static public function GetInOut(); // array of input => output
  227. protected function DoExecute()
  228. {
  229. $aTests = $this->GetInOut();
  230. if (is_array($aTests))
  231. {
  232. foreach ($aTests as $iTestId => $aTest)
  233. {
  234. $ret = call_user_func_array($this->GetCallSpec(), $aTest['args']);
  235. if ($ret != $aTest['output'])
  236. {
  237. // Note: to be improved to cope with non string parameters
  238. $this->ReportError("Found '$ret' while expecting '".$aTest['output']."'", $iTestId);
  239. }
  240. else
  241. {
  242. $this->ReportSuccess("Found the expected output '$ret'", $iTestId);
  243. }
  244. }
  245. }
  246. else
  247. {
  248. $ret = call_user_func($this->GetCallSpec());
  249. $this->ReportSuccess('Finished successfully');
  250. }
  251. }
  252. }
  253. /**
  254. * Test to check an URL (Searches for Error/Warning/Etc keywords)
  255. *
  256. * @package iTopORM
  257. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  258. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  259. * @link www.itop.com
  260. * @since 1.0
  261. * @version $itopversion$
  262. */
  263. abstract class TestUrl extends TestHandler
  264. {
  265. abstract static public function GetUrl();
  266. abstract static public function GetErrorKeywords();
  267. abstract static public function GetWarningKeywords();
  268. protected function DoExecute()
  269. {
  270. return true;
  271. }
  272. }
  273. /**
  274. * Test to check a user management module
  275. *
  276. * @package iTopORM
  277. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  278. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  279. * @link www.itop.com
  280. * @since 1.0
  281. * @version $itopversion$
  282. */
  283. abstract class TestUserRights extends TestHandler
  284. {
  285. protected function DoExecute()
  286. {
  287. return true;
  288. }
  289. }
  290. /**
  291. * Test to execute a scenario on a given DB
  292. *
  293. * @package iTopORM
  294. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  295. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  296. * @link www.itop.com
  297. * @since 1.0
  298. * @version $itopversion$
  299. */
  300. abstract class TestScenarioOnDB extends TestHandler
  301. {
  302. abstract static public function GetDBHost();
  303. abstract static public function GetDBUser();
  304. abstract static public function GetDBPwd();
  305. abstract static public function GetDBName();
  306. protected function DoPrepare()
  307. {
  308. $sDBHost = $this->GetDBHost();
  309. $sDBUser = $this->GetDBUser();
  310. $sDBPwd = $this->GetDBPwd();
  311. $sDBName = $this->GetDBName();
  312. CMDBSource::Init($sDBHost, $sDBUser, $sDBPwd);
  313. if (CMDBSource::IsDB($sDBName))
  314. {
  315. CMDBSource::DropDB($sDBName);
  316. }
  317. CMDBSource::CreateDB($sDBName);
  318. }
  319. protected function DoCleanup()
  320. {
  321. // CMDBSource::DropDB($this->GetDBName());
  322. }
  323. }
  324. /**
  325. * Test to use a business model on a given DB
  326. *
  327. * @package iTopORM
  328. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  329. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  330. * @link www.itop.com
  331. * @since 1.0
  332. * @version $itopversion$
  333. */
  334. abstract class TestBizModel extends TestHandler
  335. {
  336. // abstract static public function GetDBSubName();
  337. // abstract static public function GetBusinessModelFile();
  338. abstract static public function GetConfigFile();
  339. protected function DoPrepare()
  340. {
  341. MetaModel::Startup($this->GetConfigFile(), true); // allow missing DB
  342. MetaModel::CheckDefinitions();
  343. // something here to create records... but that's another story
  344. }
  345. protected function ResetDB()
  346. {
  347. if (MetaModel::DBExists())
  348. {
  349. MetaModel::DBDrop();
  350. }
  351. MetaModel::DBCreate();
  352. }
  353. static protected function show_list($oObjectSet)
  354. {
  355. $oObjectSet->Rewind();
  356. $aData = array();
  357. while ($oItem = $oObjectSet->Fetch())
  358. {
  359. $aValues = array();
  360. foreach(MetaModel::GetAttributesList(get_class($oItem)) as $sAttCode)
  361. {
  362. $aValues[$sAttCode] = $oItem->GetAsHTML($sAttCode);
  363. }
  364. //echo $oItem->GetKey()." => ".implode(", ", $aValues)."</br>\n";
  365. $aData[] = $aValues;
  366. }
  367. echo MyHelpers::make_table_from_assoc_array($aData);
  368. }
  369. static protected function search_and_show_list(DBObjectSearch $oMyFilter)
  370. {
  371. $oObjSet = new CMDBObjectSet($oMyFilter);
  372. echo $oMyFilter->__DescribeHTML()."' - Found ".$oObjSet->Count()." items.</br>\n";
  373. self::show_list($oObjSet);
  374. }
  375. static protected function search_and_show_list_from_sibusql($sSibuSQL)
  376. {
  377. echo $sSibuSQL."...<br/>\n";
  378. $oNewFilter = DBObjectSearch::FromSibuSQL($sSibuSQL);
  379. self::search_and_show_list($oNewFilter);
  380. }
  381. }
  382. /**
  383. * Test to execute a scenario common to any business model (tries to build all the possible queries, etc.)
  384. *
  385. * @package iTopORM
  386. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  387. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  388. * @link www.itop.com
  389. * @since 1.0
  390. * @version $itopversion$
  391. */
  392. abstract class TestBizModelGeneric extends TestBizModel
  393. {
  394. static public function GetName()
  395. {
  396. return 'Full test on a given business model';
  397. }
  398. static public function GetDescription()
  399. {
  400. return 'Systematic tests: gets each and every existing class and tries every attribute, search filters, etc.';
  401. }
  402. protected function DoPrepare()
  403. {
  404. parent::DoPrepare();
  405. if (!MetaModel::DBExists())
  406. {
  407. MetaModel::DBCreate();
  408. }
  409. // something here to create records... but that's another story
  410. }
  411. protected function DoExecute()
  412. {
  413. foreach(MetaModel::GetClasses() as $sClassName)
  414. {
  415. if (MetaModel::IsAbstract($sClassName)) continue;
  416. $oNobody = MetaModel::GetObject($sClassName, 123);
  417. $oBaby = new $sClassName;
  418. $oFilter = new DBObjectSearch($sClassName);
  419. // Challenge reversibility of SibusQL / filter object
  420. //
  421. $sExpr1 = $oFilter->ToSibuSQL();
  422. $oNewFilter = DBObjectSearch::FromSibuSQL($sExpr1);
  423. $sExpr2 = $oNewFilter->ToSibuSQL();
  424. if ($sExpr1 != $sExpr2)
  425. {
  426. $this->ReportError("Found two different SibuSQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
  427. }
  428. // Use the filter (perform the query)
  429. //
  430. $oSet = new CMDBObjectSet($oFilter);
  431. $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
  432. }
  433. return true;
  434. }
  435. }
  436. ?>