PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/functions/results.class.php

https://bitbucket.org/pfernandez/testlink1.9.6
PHP | 1965 lines | 1061 code | 227 blank | 677 comment | 187 complexity | 2879c2c132554bb016a5bcd5c053bddd MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * TestLink Open Source Project - http://testlink.sourceforge.net/
  4. * This script is distributed under the GNU General Public License 2 or later.
  5. *
  6. * @package TestLink
  7. * @author Kevin Levy, franciscom
  8. * @copyright 2004-2009, TestLink community
  9. * @version CVS: $Id: results.class.php,v 1.162 2010/08/21 15:36:11 asimon83 Exp $
  10. * @link http://www.teamst.org/index.php
  11. * @uses config.inc.php
  12. * @uses common.php
  13. *
  14. * @internal Revisions:
  15. *
  16. * 20100821 - asimon - BUGID 3682
  17. * 20100721 - asimon - BUGID 3406, 1508: changed for user assignments per build:
  18. * results_overload(), tallyBuildResults(),
  19. * getTotalsForBuilds(), createTotalsForBuilds(),
  20. * 20100518 - franciscom - BUGID 3474: Link to test case in Query Metrics Report is broken if using platforms
  21. * 20100515 - franciscom - BUGID 3438
  22. * 20090804 - franciscom - added contributed code getPriority()
  23. * 20090618 - franciscom - BUGID 0002621
  24. * 20090414 - amitkhullar - BUGID: 2374-Show Assigned User in the Not Run Test Cases Report
  25. * 20090413 - amitkhullar - BUGID 2267 - SQL Error in linked Test Cases
  26. * 20090409 - amitkhullar - Created an results_overloaded function for extending the base class
  27. results for passing extra parameters.
  28. * 20090327 - amitkhullar- BUGID 2156 - added option to get latest/all results in Query metrics report.
  29. * 20080928 - franciscom - some minor refactoring regarding keywords
  30. * 20080928 - franciscom - refactoring on buildExecutionsMap()
  31. * 20080602 - franciscom - added logic to manage version using tcversion_number
  32. * 20080513 - franciscom - getTCLink() added external_id
  33. *
  34. * 20080513 - franciscom - buildExecutionsMap() added external_id in output
  35. * 20080413 - franciscom - refactoring
  36. * 20080302 - franciscom - refactored of tally* functions, to manage
  37. * user defined test case statuses.
  38. * created tallyResults() method to remove
  39. * duplicated code. (may be can have performance side effects).
  40. *
  41. * 20071101 - franciscom - import_file_types, export_file_types
  42. * 20071013 - franciscom - changes to fix MSSQL problems
  43. * 20070916 - franciscom - refactoring to remove global coupling
  44. * changes in constructot interface()
  45. *
  46. * 20070825 - franciscom - added node_order in buildExecutionsMap()
  47. * 20070505 - franciscom - removing timer.php
  48. * 20070219 - kevinlevy - nearing completion for 1.7 release
  49. * 20060829 - kevinlevy - development in progress
  50. **/
  51. /** TBD */
  52. require_once('treeMenu.inc.php');
  53. require_once('users.inc.php');
  54. require_once('exec.inc.php'); // used for bug string lookup
  55. // BUGID 3438
  56. if (config_get('interface_bugs') != 'NO')
  57. {
  58. require_once(TL_ABS_PATH. 'lib' . DIRECTORY_SEPARATOR . 'bugtracking' .
  59. DIRECTORY_SEPARATOR . 'int_bugtracking.php');
  60. }
  61. /**
  62. * This class is encapsulates most functionality necessary to query the database
  63. * for results to publish in reports. It returns data structures to the gui layer in a
  64. * manner that are easy to display in smarty templates.
  65. *
  66. * @package TestLink
  67. * @author kevinlevy
  68. */
  69. class results extends tlObjectWithDB
  70. {
  71. /**
  72. * only call get_linked_tcversions() only once, and save it to
  73. * $this->linked_tcversions
  74. */
  75. private $linked_tcversions = null;
  76. private $suitesSelected = "";
  77. /** @var resource references passed in by constructor */
  78. var $db = null;
  79. /** @var object class references passed in by constructor */
  80. private $tplanMgr = null;
  81. private $testPlanID = -1;
  82. private $tprojectID = -1;
  83. private $testCasePrefix='';
  84. private $priorityLevelsCfg='';
  85. private $resultsCfg;
  86. private $testCaseCfg='';
  87. private $map_tc_status;
  88. private $tc_status_for_statistics;
  89. private $mapOfLastResultByOwner = null;
  90. private $mapOfLastResultByKeyword = null;
  91. private $mapOfLastResultByBuild = null;
  92. // Platform contribution
  93. private $mapOfLastResultByPrio = null;
  94. private $mapOfLastResultByPlatform = null;
  95. private $tplanName = null;
  96. // construct map linking suite ids to execution rows
  97. private $SUITE_TYPE_ID = 2;
  98. private $executionsMap = null;
  99. /**
  100. * suiteStructure is an array with pattern : name, id, array
  101. * array may contain another array in the same pattern
  102. * this is used to describe tree structure
  103. */
  104. private $suiteStructure = null;
  105. const NAME_POS = 0;
  106. const ID_POS = 1;
  107. const ARRAY_POS = 2;
  108. const ITEM_PATTERN_POS = 3;
  109. private $flatArray = null;
  110. /**
  111. * associated with flatArray
  112. */
  113. private $flatArrayIndex = 0;
  114. private $depth = 0;
  115. private $previousDepth = 0;
  116. const DEPTH_FLAT_POS = 0;
  117. const NAME_FLAT_POS = 1;
  118. const SUITE_ID_FLAT_POS = 2;
  119. const ITEM_PATTERN_FLAT_POS = 3;
  120. /** mapOfLastResult is in the following format
  121. * array ([suiteId] => array ([tcId] => Array([buildIdLastExecuted][result])))
  122. */
  123. private $mapOfLastResult = null;
  124. /**
  125. * map test suite id's to array of [total, passed, failed, blocked, not_run, other user defined]
  126. * for cases in that suite
  127. */
  128. private $mapOfSuiteSummary = null;
  129. /**
  130. * map test suite id's to array of [total, passed, failed, blocked, not_run, other user defined]
  131. * for cases in that suite and in all child suites
  132. */
  133. private $mapOfAggregate = null;
  134. /**
  135. * related to $mapOfAggregate creation
  136. * as we navigate up and down tree, $suiteId's are addded and removed from '$aggSuiteList
  137. * when totals are added for a suite, we add to all suites listed in $executionsMap
  138. * suiteIds are are registered and de-registered from aggSuiteList using
  139. * functions addToAggSuiteList(), removeFromAggSuiteList()
  140. */
  141. private $aggSuiteList = array();
  142. /**
  143. * map test suite id to number of (total, passed, failed, blocked, not run)
  144. * only counts test cases in current suite
  145. */
  146. private $mapOfTotalCases = null;
  147. private $mapOfCaseResults = null;
  148. /**
  149. * array(total cases in plan, total pass, total fail, total blocked, total not run)
  150. */
  151. private $totalsForPlan = null;
  152. /**
  153. * BUGID 3406, 1508: array similar to $totalsForPlan, but with counts for each build in it
  154. */
  155. private $totalsForBuilds = null;
  156. /**
  157. * map test case ids to array of keywords associated with test case
  158. */
  159. private $keywordData = null;
  160. /**
  161. * TO-DO check this description of this object
  162. * map of keywordIds
  163. */
  164. private $aggregateKeyResults = null;
  165. /**
  166. * TO-DO check this description of this object
  167. * map of ownerIds
  168. */
  169. private $aggregateOwnerResults = null;
  170. /**
  171. * TO-DO check this description of this object
  172. * map of buildsIds
  173. */
  174. private $aggregateBuildResults = null;
  175. private $aggregatePrioResults = null;
  176. private $aggregatePlatformResults = null;
  177. protected $latest_results;
  178. var $import_file_types = array("XML" => "XML");
  179. var $export_file_types = array("XML" => "XML");
  180. /**
  181. * class constructor
  182. * @param resource &$db reference to database handler
  183. * @param object &$tplan_mgr reference to instance of testPlan class
  184. **/
  185. public function results(&$db, &$tplan_mgr,$tproject_info, $tplan_info,
  186. $suitesSelected = 'all',
  187. $builds_to_query = -1, $lastResult = 'a',
  188. $keywordId = 0, $owner = null,
  189. $startTime = null, $endTime = null,
  190. $executor = null, $search_notes_string = null, $linkExecutionBuild = null,
  191. &$suiteStructure = null, &$flatArray = null, &$linked_tcversions = null)
  192. {
  193. $this->latest_results = 1;
  194. return $this->results_overload($db, $tplan_mgr,$tproject_info, $tplan_info,
  195. $suitesSelected ,
  196. $builds_to_query , $lastResult,
  197. $keywordId , $owner ,
  198. $startTime , $endTime ,
  199. $executor , $search_notes_string, $linkExecutionBuild ,
  200. $suiteStructure, $flatArray, $linked_tcversions);
  201. }
  202. /**
  203. * $builds_to_query = 'a' will query all build, $builds_to_query = -1 will prevent
  204. * most logic in constructor from executing/ executions table from being queried
  205. * if keyword = 0, search by keyword would not be performed
  206. * @author kevinlevy
  207. *
  208. * @internal Revisions:
  209. * 20100720 - asimon - BUGID 3406, 1508: added logic to get result counts on build level
  210. * 20090327 - amitkhullar - added parameter $latest_results to get the latest results only.
  211. * 20071013 - franciscom - changes to fix MSSQL problems
  212. * $startTime = "0000-00-00 00:00:00" -> null
  213. * $endTime = "9999-01-01 00:00:00" -> null
  214. *
  215. * 20070916 - franciscom - interface changes
  216. */
  217. public function results_overload(&$db, &$tplan_mgr,$tproject_info, $tplan_info,
  218. $suitesSelected = 'all',
  219. $builds_to_query = -1, $lastResult = 'a',
  220. $keywordId = 0, $owner = null,
  221. $startTime = null, $endTime = null,
  222. $executor = null, $search_notes_string = null, $linkExecutionBuild = null,
  223. &$suiteStructure = null, &$flatArray = null, &$linked_tcversions = null)
  224. {
  225. $this->priorityLevelsCfg = config_get('priority_levels');
  226. $this->resultsCfg = config_get('results');
  227. $this->testCaseCfg = config_get('testcase_cfg');
  228. $this->db = $db;
  229. tlObjectWithDB::__construct($db);
  230. $this->tplanMgr = $tplan_mgr;
  231. $this->map_tc_status = $this->resultsCfg['status_code'];
  232. // TestLink standard configuration is (at least for me)
  233. // not_run not available at user interface level on execution feature as choice.
  234. //
  235. // if( !isset($dummy['not_run']) )
  236. // {
  237. // $dummy['not_run']=$this->map_tc_status['not_run'];
  238. // }
  239. // This will be used to create dynamically counters if user add new status
  240. foreach( $this->resultsCfg['status_label_for_exec_ui'] as $tc_status_verbose => $label)
  241. {
  242. $this->tc_status_for_statistics[$tc_status_verbose] = $this->map_tc_status[$tc_status_verbose];
  243. }
  244. if( !isset($this->resultsCfg['status_label_for_exec_ui']['not_run']) )
  245. {
  246. $this->tc_status_for_statistics['not_run'] = $this->map_tc_status['not_run'];
  247. }
  248. $this->suitesSelected = $suitesSelected;
  249. $this->tprojectID = $tproject_info['id'];
  250. $this->testCasePrefix = $tproject_info['prefix'];
  251. $this->testPlanID = $tplan_info['id'];
  252. $this->tplanName = $tplan_info['name'];
  253. $this->suiteStructure = $suiteStructure;
  254. $this->flatArray = $flatArray;
  255. $this->linked_tcversions = $linked_tcversions;
  256. // build suiteStructure and flatArray
  257. if (($this->suiteStructure == null) && ($this->flatArray == null) && ($this->linked_tcversions == null))
  258. {
  259. list($this->suiteStructure,$this->linked_tcversions) = $this->generateExecTree($db,$keywordId, $owner);
  260. }
  261. // KL - if no builds are specified, no need to execute the following block of code
  262. if ($builds_to_query != -1) {
  263. // retrieve results from executions table
  264. // get keyword id -> keyword name pairs used in this test plan
  265. $keywords_in_tplan = $tplan_mgr->get_keywords_map($this->testPlanID,'ORDER BY keyword');
  266. // KL - 20061229 - this call may not be necessary for all reports
  267. // only those that require info on results for keywords
  268. // Map of test case ids to array of associated keywords
  269. $this->keywordData = null;
  270. if(!is_null($keywords_in_tplan))
  271. {
  272. $this->keywordData = $this->getKeywordData(array_keys($keywords_in_tplan));
  273. }
  274. //$tplan_mgr->get_keywords_tcases($this->testPlanID);
  275. // get owner id -> owner name pairs used in this test plan
  276. $arrOwners = getUsersForHtmlOptions($db);
  277. // create data object which tallies last result for each test case
  278. // this function now also creates mapOfLastResultByKeyword ???
  279. // KL - 2/01/07
  280. // we should NOT build executions map with cases that are just pass/failed/or blocked.
  281. // we should always populate the executions map with all results
  282. // and then programmatically figure out the last result
  283. // if you just query the executions table for those rows with status = $this->map_tc_status['passed']
  284. // that is not the way to determine last result
  285. $all_results = $this->latest_results;
  286. $this->executionsMap = $this->buildExecutionsMap($builds_to_query, 'a', $keywordId,
  287. $owner, $startTime, $endTime, $executor,
  288. $search_notes_string, $linkExecutionBuild,
  289. $all_results);
  290. // new dBug($this->executionsMap);
  291. $this->createMapOfLastResult($this->suiteStructure, $this->executionsMap, $lastResult);
  292. $this->aggregateKeywordResults = $this->tallyKeywordResults($this->mapOfLastResultByKeyword, $keywords_in_tplan);
  293. $this->aggregateOwnerResults = $this->tallyOwnerResults($this->mapOfLastResultByOwner, $arrOwners);
  294. // create data object which tallies totals for individual suites
  295. // child suites are NOT taken into account in this step
  296. $this->createMapOfSuiteSummary($this->mapOfLastResult);
  297. // create data object which tallies totals for suites taking
  298. // child suites into account
  299. $this->createAggregateMap($this->suiteStructure, $this->mapOfSuiteSummary);
  300. $this->totalsForPlan = $this->createTotalsForPlan($this->suiteStructure);
  301. // must be done after totalsForPlan is performed because the total # of cases is needed
  302. // BUGID 3682
  303. $arrBuilds = $tplan_mgr->get_builds($this->testPlanID, testplan::GET_ACTIVE_BUILD);
  304. // 3406, 1508 - we need the totals per build here, not for the whole plan anymore
  305. //$this->aggregateBuildResults = $this->tallyBuildResults($this->mapOfLastResultByBuild,
  306. // $arrBuilds, $this->totalsForPlan);
  307. $this->totalsForBuilds = $this->createTotalsForBuilds($arrBuilds);
  308. $this->aggregateBuildResults = $this->tallyBuildResults($this->mapOfLastResultByBuild,
  309. $arrBuilds, $this->totalsForBuilds);
  310. } // end if block
  311. } // end results constructor
  312. /**
  313. * get_export_file_types
  314. * @return array map of
  315. * key: export file type code
  316. * value: export file type verbose description
  317. */
  318. function get_export_file_types()
  319. {
  320. return $this->export_file_types;
  321. }
  322. /**
  323. * get_import_file_types
  324. * @return array map of
  325. * key: export file type code
  326. * value: export file type verbose description
  327. */
  328. function get_import_file_types()
  329. {
  330. return $this->import_file_types;
  331. }
  332. /**
  333. * tallyKeywordResults($keywordResults, $keywordIdNamePairs)
  334. *
  335. * @param array $keywordResults Array ([keyword id] => Array ( [test case id] => result ))
  336. * example:
  337. * <code>
  338. * Array ( [128] => Array ( [14308] => p [14309] => n [14310] => n [14311] => f [14312] => n [14313] => n )
  339. * [11] => Array ( [14309] => n [14310] => n [14311] => f [14312] => n [14313] => n ))
  340. * </code>
  341. *
  342. * @return array map indexed using Keyword ID, where each element is a map with following structure:
  343. * <code>
  344. * [keyword_name] => K1
  345. * [total_tc] => 2
  346. * [percentage_completed] => 100.00
  347. * [details] => Array
  348. * (
  349. * [passed] => Array
  350. * (
  351. * [qty] => 1
  352. * [percentage] => 50.00
  353. * )
  354. * [failed] => Array
  355. * (
  356. * [qty] => 1
  357. * [percentage] => 50.00
  358. * )
  359. * [blocked] => Array
  360. * (
  361. * [qty] => 0
  362. * [percentage] => 0.00
  363. * )
  364. * [unknown] => Array
  365. * (
  366. * [qty] => 0
  367. * [percentage] => 0.00
  368. * )
  369. * [not_run] => Array
  370. * (
  371. * [qty] => 0
  372. * [percentage] => 0.00
  373. * )
  374. * )
  375. * )
  376. * </code>
  377. * IMPORTANT: keys on details map dependends of configuration map $tlCfg->results['status_label']
  378. */
  379. private function tallyKeywordResults($keywordResults, $keywordIdNamePairs)
  380. {
  381. if ($keywordResults == null)
  382. {
  383. return null;
  384. }
  385. $rValue = null;
  386. foreach($keywordResults as $keywordId => $results)
  387. {
  388. $item_name = 'keyword_name';
  389. $element = $this->tallyResults($results,sizeOf($results),$item_name);
  390. $element[$item_name] = $keywordIdNamePairs[$keywordId];
  391. $rValue[$keywordId] = $element;
  392. }
  393. return $rValue;
  394. }
  395. /**
  396. *
  397. * @param array $ownerResults format:
  398. * <code>Array ([owner id] => Array ( [test case id] => result ))</code>
  399. *
  400. * @return array map
  401. * Example of output format :
  402. * <code>
  403. * [tester_name] => johndoe
  404. * [total_tc] => 2
  405. * [percentage_completed] => 100.00
  406. * [details] => Array
  407. * (
  408. * [passed] => Array
  409. * (
  410. * [qty] => 1
  411. * [percentage] => 50.00
  412. * )
  413. * [failed] => Array
  414. * (
  415. * [qty] => 1
  416. * [percentage] => 50.00
  417. * )
  418. * [blocked] => Array
  419. * (
  420. * [qty] => 0
  421. * [percentage] => 0.00
  422. * )
  423. * [unknown] => Array
  424. * (
  425. * [qty] => 0
  426. * [percentage] => 0.00
  427. * )
  428. * [not_run] => Array
  429. * (
  430. * [qty] => 0
  431. * [percentage] => 0.00
  432. * )
  433. * )
  434. * )
  435. * </code>
  436. *
  437. * IMPORTANT: keys on details map dependends of configuration map $tlCfg->results['status_label']
  438. */
  439. private function tallyOwnerResults($ownerResults, $ownerIdNamePairs)
  440. {
  441. if ($ownerResults == null)
  442. {
  443. return;
  444. }
  445. $no_tester_assigned = lang_get('unassigned');
  446. $rValue = null;
  447. foreach($ownerResults as $ownerId => $results)
  448. {
  449. $item_name = 'tester_name';
  450. // Calculates number of tc assignes to user
  451. $num = 0;
  452. foreach($results as $tc_id => $tc_info)
  453. {
  454. foreach ($tc_info as $platform_id => $platform)
  455. {
  456. $num++;
  457. }
  458. }
  459. $element = $this->tallyResults($results,$num,$item_name);
  460. $element[$item_name] = ($ownerId == -1) ? $no_tester_assigned : $ownerIdNamePairs[$ownerId];
  461. $rValue[$ownerId] = $element;
  462. }
  463. return $rValue;
  464. }
  465. /**
  466. *
  467. * parameter1 format:
  468. * Array ([owner id] => Array ( [test case id] => result ))
  469. *
  470. * @return array map
  471. * <code>Array ( [owner id] => Array ( total, passed, failed, blocked, not run))</code>
  472. *
  473. * @internal revisions:
  474. * 20100721 - asimon - BUGID 3406, 1508
  475. */
  476. private function tallyBuildResults($buildResults, $arrBuilds, $finalResults)
  477. {
  478. if ($buildResults == null)
  479. {
  480. return null;
  481. }
  482. // OK go ahead
  483. // 3406, 1508
  484. //$totalCases = $finalResults['total'];
  485. $na_string = lang_get('not_aplicable');
  486. $rValue = null;
  487. foreach($arrBuilds as $buildId => $buildInfo)
  488. {
  489. $item_name='build_name';
  490. $results = isset($buildResults[$buildId]) ? $buildResults[$buildId] : array();
  491. // 3406, 1508 - total cases is now an array with totals for each build ID
  492. $totalCases = $finalResults[$buildId]['total'];
  493. $element=$this->tallyResults($results,$totalCases,$item_name);
  494. if (!is_null ($element))
  495. {
  496. $element[$item_name]=$buildInfo['name'];
  497. $rValue[$buildId] = $element;
  498. // 3406, 1508: here we need to insert the correct "not run" value now
  499. // and the percentages need to be re-calculated after that of course
  500. $not_run_count = $this->tplanMgr->assignment_mgr->get_not_run_tc_count_per_build($buildId);
  501. $not_run_percentage = ($totalCases != 0) ?
  502. number_format($not_run_count / $totalCases * 100, 2) : $na_string;
  503. $rValue[$buildId]['details']['not_run']['qty'] = $not_run_count;
  504. $rValue[$buildId]['details']['not_run']['percentage'] = $not_run_percentage;
  505. $rValue[$buildId]['percentage_completed'] = 100 - $not_run_percentage;
  506. }
  507. } // end foreach
  508. unset($element);
  509. unset($results);
  510. return $rValue;
  511. }
  512. /**
  513. * Aggregates results based on priority.
  514. * @see aggregateOwnerResults()
  515. * @param $prioResults array
  516. * <code> Array ([priority] => Array ( [tc_id] => Array( [platform_id] => result ))) </code>
  517. *
  518. * @return array map
  519. * <code>Array ( [priority] => Array ( total, passed, failed, blocked, not run))</code>
  520. */
  521. private function tallyPriorityResults($prioResults)
  522. {
  523. if ($prioResults == null)
  524. {
  525. return null;
  526. }
  527. $urgencyCfg = config_get('urgency');
  528. $rValue = null;
  529. foreach($prioResults as $prio => $results)
  530. {
  531. $item_name='priority';
  532. // Calculates number of tc in this prio
  533. $num = 0;
  534. foreach($results as $tc_id => $tc_info) {
  535. foreach ($tc_info as $platform_id => $platform) {
  536. $num++;
  537. }
  538. }
  539. $element=$this->tallyResults($results,$num,$item_name);
  540. if (!is_null ($element))
  541. {
  542. $element[$item_name]=lang_get($urgencyCfg["code_label"][$prio]);
  543. $rValue[$prio] = $element;
  544. }
  545. } // end foreach
  546. // Sort returning array from high to low priority
  547. krsort($rValue);
  548. unset($element);
  549. unset($results);
  550. return $rValue;
  551. }
  552. /**
  553. * Aggregates results based on platform.
  554. * @see aggregateOwnerResults()
  555. * @param $prioResults array
  556. * <code> Array ([platform] => Array ( [tc_id] => Array( [platform_id] => result ))) </code>
  557. *
  558. * @return array map
  559. * <code>Array ( [priority] => Array ( total, passed, failed, blocked, not run))</code>
  560. */
  561. // private function tallyPlatformResults($platformResults, $platforms)
  562. // {
  563. // echo __FUNCTION__;
  564. // if ($platformResults == null)
  565. // {
  566. // return null;
  567. // }
  568. //
  569. // $rValue = null;
  570. // foreach($platformResults as $platform_id => $results)
  571. // {
  572. // $item_name='platform';
  573. // // Calculates number of tc in this platform.
  574. // $num = 0;
  575. // foreach($results as $tc_id => $tc_info) {
  576. // foreach ($tc_info as $platform) {
  577. // $num++;
  578. // }
  579. // }
  580. // $element=$this->tallyResults($results,$num,$item_name);
  581. // if (!is_null ($element))
  582. // {
  583. // $element[$item_name]=$platforms[$platform_id];
  584. // $rValue[$platform_id] = $element;
  585. // }
  586. // } // end foreach
  587. //
  588. // unset($element);
  589. // unset($results);
  590. //
  591. // return $rValue;
  592. // }
  593. /**
  594. * @return array total / pass / fail / blocked / not run results for each keyword id
  595. */
  596. public function getAggregateKeywordResults() {
  597. return $this->aggregateKeywordResults;
  598. }
  599. /**
  600. * @return array total / pass / fail / blocked / not run results for each owner id
  601. * unassigned test cases show up under owner id = -1
  602. */
  603. public function getAggregateOwnerResults() {
  604. return $this->aggregateOwnerResults;
  605. }
  606. /**
  607. * @return array total / pass / fail / blocked / not run results for each build id
  608. */
  609. public function getAggregateBuildResults() {
  610. return $this->aggregateBuildResults;
  611. }
  612. /**
  613. * Aggregates and returns results grouped by priority
  614. * @return array total / pass / fail / blocked / not run results for each build id
  615. */
  616. public function getAggregatePriorityResults()
  617. {
  618. if ($this->aggregatePrioResults == null) {
  619. $this->aggregatePrioResults = $this->tallyPriorityResults($this->mapOfLastResultByPrio);
  620. }
  621. return $this->aggregatePrioResults;
  622. }
  623. /**
  624. * Aggregates and returns results grouped by platform
  625. * @return array total / pass / fail / blocked / not run results for each build id
  626. */
  627. // public function getAggregatePlatformResults()
  628. // {
  629. // if ($this->aggregatePlatformResults == null)
  630. // {
  631. // $platforms = $this->tplanMgr->getPlatforms($this->testPlanID,'map');
  632. // $this->aggregatePlatformResults = $this->tallyPlatformResults($this->mapOfLastResultByPlatform, $platforms);
  633. // }
  634. // return $this->aggregatePlatformResults;
  635. // }
  636. /**
  637. * @TODO rename this method to getExecutionsMap()
  638. * (resultsTC.php is 1 file (may not be only file) that references this method)
  639. * @return array
  640. */
  641. public function getSuiteList(){
  642. return $this->executionsMap;
  643. }
  644. /**
  645. * @return array array which describes suite hierachy
  646. */
  647. public function getSuiteStructure(){
  648. return $this->suiteStructure;
  649. }
  650. public function getLinkedTCVersions(){
  651. return $this->linked_tcversions;
  652. }
  653. /**
  654. * @return array
  655. */
  656. public function getMapOfSuiteSummary(){
  657. return $this->mapOfSuiteSummary;
  658. }
  659. /**
  660. * @return array
  661. */
  662. public function getMapOfLastResult() {
  663. return $this->mapOfLastResult;
  664. }
  665. /**
  666. * @return array
  667. */
  668. public function getAggregateMap(){
  669. return $this->mapOfAggregate;
  670. }
  671. /**
  672. * @return array
  673. */
  674. public function getTotalsForPlan()
  675. {
  676. return $this->totalsForPlan;
  677. }
  678. /**
  679. * BUGID 3406, 1508
  680. * @author Andreas Simon
  681. * @return array
  682. */
  683. public function getTotalsForBuild()
  684. {
  685. return $this->totalsForBuilds;
  686. }
  687. /**
  688. * @return array single-dimension array with pattern level, suite name, suite id
  689. */
  690. public function getFlatArray(){
  691. return $this->flatArray;
  692. }
  693. /**
  694. * @param array $results map: key tc_id => value status_code
  695. * @return mixed array or null
  696. */
  697. private function tallyResults($results,$totalCases,$item_name=null)
  698. {
  699. if ($results == null)
  700. {
  701. return null;
  702. }
  703. // OK go ahead
  704. // 3406
  705. $na_string = lang_get('not_aplicable');
  706. $code_verbose=array_flip($this->tc_status_for_statistics);
  707. $element = null;
  708. foreach($this->tc_status_for_statistics as $status_verbose => $status_code)
  709. {
  710. $total[$status_verbose]=0;
  711. $percentage[$status_verbose]=0;
  712. }
  713. $dummy=0;
  714. foreach($results as $tc_id => $tc_info)
  715. {
  716. foreach((array)$tc_info as $platform_id => $result_code) {
  717. $status_verbose=$code_verbose[$result_code];
  718. // Check if user has configured and add not_run.
  719. // Standard TestLink behavior:
  720. // 1. do not show not_run as a choice on execute pages
  721. // 2. do not save on DB not_run executions
  722. //
  723. if( $status_verbose !='' && $status_verbose != 'not_run')
  724. {
  725. $total[$status_verbose]++;
  726. $dummy++;
  727. }
  728. }
  729. }
  730. // not_run is an special status
  731. $total['not_run'] = abs($totalCases - $dummy);
  732. $percentage['not_run'] = ($totalCases != 0) ?
  733. number_format((($total['not_run']) / $totalCases) * 100,2) : $na_string;
  734. $percentCompleted = 0;
  735. if ($totalCases != 0)
  736. {
  737. $percentCompleted = (($totalCases - $total['not_run']) / $totalCases) * 100;
  738. foreach($this->tc_status_for_statistics as $status_verbose => $status_code)
  739. {
  740. $percentage[$status_verbose]=(($total[$status_verbose]) / $totalCases) * 100;
  741. $percentage[$status_verbose]=number_format($percentage[$status_verbose],2);
  742. }
  743. }
  744. $percentCompleted = number_format($percentCompleted,2);
  745. // Because I want to have this as first key on map, just for easy reading.
  746. // Value will be setted by caller.
  747. if( !is_null($item_name) )
  748. {
  749. $element[$item_name]='';
  750. }
  751. $element['total_tc']=$totalCases;
  752. $element['percentage_completed']=$percentCompleted;
  753. $element['details']=array();
  754. foreach($total as $status_verbose => $counter)
  755. {
  756. $element['details'][$status_verbose]['qty']=$counter;
  757. $element['details'][$status_verbose]['percentage']=$percentage[$status_verbose];
  758. }
  759. return $element;
  760. } // end function
  761. function tallyResults2($results,$totalCases)
  762. {
  763. if ($results == null)
  764. {
  765. return null;
  766. }
  767. // not_run is an special status
  768. $total['not_run'] = abs($totalCases - $dummy);
  769. $percentage['not_run']=number_format((($total['not_run']) / $totalCases) * 100,2);
  770. $keySet = array_keys($results);
  771. foreach($keySet as $keyID)
  772. {
  773. $results[$keyID]['percentage_completed'] = 0;
  774. $totalCases = $results[$keyID]['total_tc'];
  775. $target = &$results[$keyID]['details'];
  776. if ($totalCases != 0)
  777. {
  778. $results[$keyID]['percentage_completed'] =
  779. number_format((($totalCases - $target['not_run']['qty']) / $totalCases) * 100,2);
  780. }
  781. foreach($target as $status_verbose => $qty)
  782. {
  783. $target[$status_verbose]['percentage']=(($target[$status_verbose]['qty']) / $totalCases) * 100;
  784. $target[$status_verbose]['percentage']=number_format($target[$status_verbose]['percentage'],2);
  785. }
  786. }
  787. return $results;
  788. } // end function
  789. /**
  790. * Gets the user for a specific feature_id
  791. * @author amitkhullar
  792. *
  793. * @return integer User identifier
  794. */
  795. function getUserForFeature($feature_id)
  796. {
  797. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  798. $sql = "/* $debugMsg */ ";
  799. $sql .= " SELECT user_id FROM {$this->tables['user_assignments']} " .
  800. " user_assignments WHERE feature_id = " . $feature_id ;
  801. $owner_row = $this->db->fetchFirstRow($sql,'testcase_id', 1);
  802. $owner_id = $owner_row['user_id'] == '' ? -1 : $owner_row['user_id'];
  803. return $owner_id;
  804. } // end function
  805. /**
  806. * Fill $this->mapOfLastResult - which provides information on the last result
  807. * for each test case.
  808. *
  809. * $this->mapOfLastResult is an array of suite ids
  810. * each suiteId -> arrayOfTCresults, arrayOfSummaryResults
  811. * arrayOfTCresults -> array of rows containing (buildIdLastExecuted, result) where row id = testcaseId
  812. *
  813. * currently it does not account for user expliting marking a case "not run".
  814. *
  815. * @author kevinlevy
  816. *
  817. * @return void
  818. *
  819. * @internal Revisions:
  820. *
  821. * 20070919 - franciscom - interface changes
  822. * 20070825 - franciscom - added node_order
  823. */
  824. private function addLastResultToMap($suiteId, $suiteName, $exec,$lastResultToTrack)
  825. {
  826. $testcase_id = $exec['testcaseID'];
  827. $platform_id = $exec['platform_id'];
  828. $external_id = $exec['external_id'];
  829. $buildNumber = $exec['build_id'];
  830. $result = $exec['status'];
  831. $tcversion_id = $exec['tcversion_id'];
  832. // echo __FUNCTION__ . 'tcversion id ' . $tcversion_id . '<br>';
  833. // 20080602 - franciscom
  834. // Maybe this check is not more needed, because $exec has been changed using same logic
  835. if( isset($exec['tcversion_number']) && !is_null($exec['tcversion_number']) )
  836. {
  837. $version=$exec['tcversion_number'];
  838. }
  839. else
  840. {
  841. $version=$exec['version'];
  842. }
  843. $execution_ts=$exec['execution_ts'];
  844. $notes=$exec['notes'];
  845. $executions_id=$exec['executions_id'];
  846. $name=$exec['name'];
  847. $tester_id=$exec['tester_id'];
  848. $feature_id=$exec['feature_id'];
  849. $assigner_id=$exec['assigner_id'];
  850. if ($buildNumber)
  851. {
  852. $this->mapOfLastResultByBuild[$buildNumber][$testcase_id][$platform_id] = $result;
  853. }
  854. $owner_id = $this->getUserForFeature($feature_id);
  855. $associatedKeywords = null;
  856. if ($this->keywordData != null && array_key_exists($testcase_id, $this->keywordData))
  857. {
  858. $associatedKeywords = $this->keywordData[$testcase_id];
  859. }
  860. $doInsert = false;
  861. // handle case where suite has already been added to mapOfLastResult
  862. if ($this->mapOfLastResult && array_key_exists($suiteId, $this->mapOfLastResult))
  863. {
  864. // handle case where both suite and test case have been added to elmapOfLastResult
  865. if (array_key_exists($testcase_id, $this->mapOfLastResult[$suiteId]))
  866. {
  867. // handle case where all of suite, test case and platform have been added to mapOfLastResult
  868. if (array_key_exists($platform_id, $this->mapOfLastResult[$suiteId][$testcase_id]))
  869. {
  870. $buildInMap = $this->mapOfCaseResults[$testcase_id]['buildNumber'];
  871. $execIDInMap = $this->mapOfCaseResults[$testcase_id]['execID'];
  872. if (($buildInMap < $buildNumber) || ($buildInMap == $buildNumber && $execIDInMap < $executions_id))
  873. {
  874. $doInsert = true;
  875. }
  876. }
  877. else
  878. {
  879. $doInsert = true;
  880. }
  881. }
  882. else
  883. {
  884. $doInsert = true;
  885. }
  886. }
  887. else
  888. {
  889. $doInsert = true;
  890. }
  891. if ($doInsert)
  892. {
  893. $this->mapOfLastResultByOwner[$owner_id][$testcase_id][$platform_id] = $result;
  894. // priorities
  895. // echo __FUNCTION__ . ' LINE::' . __LINE__ .'<br> - tcversion_id=' . $tcversion_id . '<br>';
  896. $prio = $this->getPriority($this->testPlanID, $tcversion_id);
  897. $this->mapOfLastResultByPrio[$prio][$testcase_id][$platform_id] = $result;
  898. // 20090804 - Eloff
  899. // This structure might look weird, but is needed to reuse aggregation code
  900. // $this->mapOfLastResultByPlatform[$platform_id][$testcase_id][$platform_id] = $result;
  901. $qta_loops=sizeof($associatedKeywords);
  902. for ($i = 0;$i <$qta_loops ; $i++)
  903. {
  904. $this->mapOfLastResultByKeyword[$associatedKeywords[$i]][$testcase_id] = $result;
  905. }
  906. $this->mapOfCaseResults[$testcase_id]['buildNumber'] = $buildNumber;
  907. $this->mapOfCaseResults[$testcase_id]['execID'] = $executions_id;
  908. $this->mapOfLastResult[$suiteId][$testcase_id][$platform_id] = array("buildIdLastExecuted" => $buildNumber,
  909. "result" => $result,
  910. "tcversion_id" => $tcversion_id,
  911. "platform_id" => $platform_id,
  912. "external_id" => $external_id,
  913. "version" => $version,
  914. "execution_ts" => $execution_ts,
  915. "notes" => $notes,
  916. "suiteName" => $suiteName,
  917. "executions_id" => $executions_id,
  918. "name" => $name,
  919. "tester_id" => $tester_id);
  920. }
  921. } // end function
  922. /**
  923. * Creates statistics on each suite
  924. * @return void
  925. */
  926. private function createMapOfSuiteSummary(&$mapOfLastResult)
  927. {
  928. if ($mapOfLastResult)
  929. {
  930. $code_verbose=array_flip($this->tc_status_for_statistics);
  931. $code_verbose[$this->map_tc_status['not_run']]='not_run';
  932. foreach($mapOfLastResult as $suiteId => $tcaseResults)
  933. {
  934. foreach($this->tc_status_for_statistics as $status_verbose => $status_code)
  935. {
  936. $total[$status_verbose]=0;
  937. }
  938. $total['not_run']=0;
  939. $total['total'] = 0;
  940. foreach($tcaseResults as $testcase_id => $platformResults) {
  941. foreach($platformResults as $platform_id => $value)
  942. {
  943. $currentResult = $value['result'];
  944. $status_verbose=$code_verbose[$currentResult];
  945. $total[$status_verbose]++;
  946. $total['total']++;
  947. }
  948. $this->mapOfSuiteSummary[$suiteId] = $total;
  949. }
  950. }
  951. } // end if
  952. } // end function
  953. /**
  954. * tallies total cases, total pass/fail/blocked/not run for each suite
  955. * it takes into account sub-suite tallies within that suite
  956. * ex : if suite A contains suites A.1 and A.2, this function
  957. * adds up A.1, A.2, and test cases within A
  958. */
  959. private function createAggregateMap(&$suiteStructure, &$mapOfSuiteSummary)
  960. {
  961. $loop_qty=count($suiteStructure);
  962. for ($idx = 0; $idx < $loop_qty; $idx++ )
  963. {
  964. $suiteId = 0;
  965. $tpos=$idx % self::ITEM_PATTERN_POS;
  966. if ($tpos == self::ID_POS)
  967. {
  968. // register a suite that we will use to increment aggregate results for
  969. $suiteId = $suiteStructure[$idx];
  970. array_push($this->aggSuiteList, $suiteId);
  971. if ($mapOfSuiteSummary && array_key_exists($suiteId, $mapOfSuiteSummary))
  972. {
  973. $summaryArray = $mapOfSuiteSummary[$suiteId];
  974. $this->addResultsToAggregate($summaryArray);
  975. }
  976. }
  977. elseif ($tpos == self::ARRAY_POS)
  978. {
  979. if (is_array($suiteStructure[$idx]))
  980. {
  981. // go get child totals
  982. $newSuiteStructure = $suiteStructure[$idx];
  983. $this->createAggregateMap($newSuiteStructure, $mapOfSuiteSummary);
  984. }
  985. // it's very important to pop a suite off the list at this point
  986. // and only this point
  987. array_pop($this->aggSuiteList);
  988. }
  989. } // end for
  990. } // end function
  991. /**
  992. * iterates over top level suites and adds up totals using data from mapOfAggregate
  993. */
  994. private function createTotalsForPlan($suiteStructure)
  995. {
  996. $counters['total']=0;
  997. $counters['not_run']=0;
  998. foreach($this->tc_status_for_statistics as $status_verbose => $status_code)
  999. {
  1000. $counters[$status_verbose]=0;
  1001. }
  1002. $loop_qty=count($suiteStructure);
  1003. for ($idx = 0 ; $idx < $loop_qty ; $idx++)
  1004. {
  1005. if (($idx % self::ITEM_PATTERN_POS) == self::ID_POS)
  1006. {
  1007. $suiteId = $suiteStructure[$idx];
  1008. $resultsForSuite = isset($this->mapOfAggregate[$suiteId]) ? $this->mapOfAggregate[$suiteId] : null;
  1009. if( !is_null($resultsForSuite) )
  1010. {
  1011. foreach($counters as $code_verbose => $value)
  1012. {
  1013. $counters[$code_verbose]+=$resultsForSuite[$code_verbose];
  1014. }
  1015. }
  1016. } // end if
  1017. }
  1018. return $counters;
  1019. } // end function
  1020. /**
  1021. * For BUGID 3406, 1508: New function to get counts on build level instead of testplan level
  1022. *
  1023. * @author Andreas Simon
  1024. * @param array $arrBuilds Array with information about the builds for this testplan.
  1025. * @return array $counters Array similar to $this->totalsForPlan, but with correct numbers per build
  1026. */
  1027. private function createTotalsForBuilds($arrBuilds) {
  1028. $counters = array();
  1029. // first get totals from plan, then replace "wrong" values
  1030. foreach ($arrBuilds as $build_id => $build_info) {
  1031. $counters[$build_id] = $this->totalsForPlan;
  1032. // replace "total" value
  1033. $total = $this->tplanMgr->assignment_mgr->get_count_of_assignments_for_build_id($build_id);
  1034. $counters[$build_id]['total'] = $total;
  1035. // replace "not run" value
  1036. $not_run = $this->tplanMgr->assignment_mgr->get_not_run_tc_count_per_build($build_id);
  1037. $counters[$build_id]['not_run'] = $not_run;
  1038. }
  1039. return $counters;
  1040. } // end of method
  1041. /**
  1042. * @return array map with following keys:
  1043. * 'total','not_run', other keys depends of status configured by user
  1044. * If users leave untouched TestLink Factory configuration:
  1045. * 'total','not_run','passed','failed','blocked'
  1046. */
  1047. private function addResultsToAggregate($results)
  1048. {
  1049. $loop_qty=count($this->aggSuiteList);
  1050. for ($idx = 0 ; $idx < $loop_qty ; $idx++)
  1051. {
  1052. $suiteId = $this->aggSuiteList[$idx];
  1053. $currentSuite = null;
  1054. if ($this->mapOfAggregate && array_key_exists($suiteId, $this->mapOfAggregate))
  1055. {
  1056. $currentSuite = $this->mapOfAggregate[$suiteId];
  1057. }
  1058. else
  1059. {
  1060. $currentSuite['total'] = 0;
  1061. foreach($this->tc_status_for_statistics as $status_verbose => $status_code)
  1062. {
  1063. $currentSuite[$status_verbose]=0;
  1064. }
  1065. $currentSuite['not_run'] = 0;
  1066. }
  1067. foreach($currentSuite as $key => $value)
  1068. {
  1069. $currentSuite[$key] += $results[$key];
  1070. }
  1071. $this->mapOfAggregate[$suiteId] = $currentSuite;
  1072. }
  1073. } // end function
  1074. /**
  1075. * @return array map testcase_id, keyword_id
  1076. */
  1077. private function getKeywordData($keywordsInPlan)
  1078. {
  1079. $CUMULATIVE=1;
  1080. // limit the sql query to just those keys in this test plan
  1081. if ($keywordsInPlan == null) {
  1082. return null;
  1083. }
  1084. $keys = implode(',',$keywordsInPlan);
  1085. $sql = " SELECT testcase_id, keyword_id" .
  1086. " FROM {$this->tables['testcase_keywords']}" .
  1087. " WHERE keyword_id IN ($keys)";
  1088. $returnMap = $this->db->fetchColumnsIntoMap($sql,'testcase_id', 'keyword_id',$CUMULATIVE);
  1089. return $returnMap;
  1090. } // end function
  1091. /**
  1092. *
  1093. */
  1094. private function createMapOfLastResult(&$suiteStructure, &$executionsMap, $lastResult)
  1095. {
  1096. $suiteName = null;
  1097. $totalSuites = count($suiteStructure);
  1098. for ($i = 0; $i < $totalSuites; $i++)
  1099. {
  1100. if (($i % self::ITEM_PATTERN_POS) == self::NAME_POS)
  1101. {
  1102. $suiteName = $suiteStructure[$i];
  1103. }
  1104. elseif (($i % self::ITEM_PATTERN_POS) == self::ID_POS)
  1105. {
  1106. $suiteId = $suiteStructure[$i];
  1107. if( isset($executionsMap[$suiteId]) )
  1108. {
  1109. $totalCases = count($executionsMap[$suiteId]);
  1110. for ($j = 0 ; $j < $totalCases; $j++)
  1111. {
  1112. $cexec = $executionsMap[$suiteId][$j];
  1113. $this->addLastResultToMap($suiteId, $suiteName,$cexec,$lastResult);
  1114. }
  1115. }
  1116. }
  1117. elseif (($i % self::ITEM_PATTERN_POS) == self::ARRAY_POS)
  1118. {
  1119. if (is_array($suiteStructure[$i]))
  1120. {
  1121. $childSuite = $suiteStructure[$i];
  1122. $summaryTreeForChild = $this->createMapOfLastResult($childSuite, $executionsMap, $lastResult);
  1123. }
  1124. } // end elseif
  1125. } // end for loop
  1126. } // end function
  1127. /**
  1128. * Builds $executionsMap map.
  1129. * $executionsMap contains all execution information for suites and test cases.
  1130. *
  1131. *
  1132. * $executionsMap = [testsuite_id_1_array, test_suite_id_2_array, ...]
  1133. *
  1134. * testsuite_id_1_array = []
  1135. * all test cases are included, even cases that have not been executed yet
  1136. *
  1137. * @internal Revisions:
  1138. *
  1139. * 20100518 - franciscom - BUGID 3474: Link to test case in Query Metrics Report is broken if using platforms
  1140. * 20090302 - amitkhullar - added a parameter $all_results to get latest results (0) only otherwise
  1141. * all results are displayed in reports (1).
  1142. * 20080928 - franciscom - seems that adding a control to avoid call to buildBugString()
  1143. * reduces dramatically memory usage();
  1144. * IMPORTANT:
  1145. * we need to refactor this method, because if we had to call buildBugsString()
  1146. * probably will crash again.
  1147. * We need to think about function that got bug for all test cases, with one
  1148. * call, may be is the solution.
  1149. *
  1150. * 20070916 - franciscom - removed session coupling
  1151. * added node_order
  1152. */
  1153. private function buildExecutionsMap($builds_to_query, $lastResult = 'a', $keyword = 0,
  1154. $owner = null, $startTime, $endTime, $executor,
  1155. $search_notes_string, $executeLinkBuild, $all_results = 1)
  1156. {
  1157. $searchBugs= config_get('bugInterfaceOn');
  1158. // first make sure we initialize the executionsMap
  1159. // otherwise duplicate executions will be added to suites
  1160. $executionsMap = null;
  1161. // map for adding SuiteName directly to every TC
  1162. $allSuites = $this->getAllSuites();
  1163. // for execution link
  1164. $canExecute = has_rights($this->db,"tp_execute");
  1165. // Build Sql additional filters
  1166. $sqlFilters='';
  1167. if( !is_null($startTime) )
  1168. {
  1169. $sqlFilters .= " AND execution_ts > '{$startTime}'";
  1170. }
  1171. if( !is_null($endTime) )
  1172. {
  1173. $sqlFilters .= " AND execution_ts < '{$endTime}' ";
  1174. }
  1175. if (($lastResult == $this->map_tc_status['passed']) || ($lastResult == $this->map_tc_status['failed']) ||
  1176. ($lastResult == $this->map_tc_status['blocked'])){
  1177. $sqlFilters .= " AND status = '" . $lastResult . "' ";
  1178. }
  1179. if (($builds_to_query != -1) && ($builds_to_query != 'a')) {
  1180. $sqlFilters .= " AND build_id IN ($builds_to_query) ";
  1181. }
  1182. // BUGID 2023
  1183. if (!is_null($executor) && $executor != '' && $executor != TL_USER_ANYBODY)
  1184. {
  1185. $sqlFilters .= " AND tester_id = $executor ";
  1186. }
  1187. if ($search_notes_string != null) {
  1188. $sqlFilters .= " AND notes LIKE '%" . $search_notes_string ."%' ";
  1189. }
  1190. $suffixLink = htmlspecialchars($this->testCasePrefix . $this->testCaseCfg->glue_character);
  1191. foreach($this->linked_tcversions as $tcase_info)
  1192. {
  1193. foreach($tcase_info as $index => $info)
  1194. {
  1195. $testcaseID = $info['tc_id'];
  1196. $executionExists = true;
  1197. $currentSuite = null;
  1198. if (!$executionsMap || !(array_key_exists($info['testsuite_id'], $executionsMap)))
  1199. {
  1200. $currentSuite = array();
  1201. }
  1202. else
  1203. {
  1204. $currentSuite = $executionsMap[$info['testsuite_id']];
  1205. }
  1206. $version = $info['version'];
  1207. if(isset($info['tcversion_number']) && !is_null($info['tcversion_number']))
  1208. {
  1209. $version = $info['tcversion_number'];
  1210. }
  1211. ;
  1212. $owner_id = $this->getUserForFeature($info['feature_id']);
  1213. // BUGID - 2374: Show Assigned User in the Not Run Test Cases Report
  1214. $infoToSave = array('testcaseID' => $testcaseID,
  1215. 'platform_id' => $info['platform_id'],
  1216. 'testcasePrefix' => $this->testCasePrefix . $this->testCaseCfg->glue_character,
  1217. 'external_id' => $info['external_id'],
  1218. 'tcversion_id' => $info['tcversion_id'],
  1219. 'version' => $version,
  1220. 'build_id' => '',
  1221. 'tester_id' => $owner_id,
  1222. 'execution_ts' => '',
  1223. 'status' => $this->map_tc_status['not_run'],
  1224. 'executions_id' => '',
  1225. 'notes' => '',
  1226. 'bugString' => '',
  1227. 'name' => $info['name'],
  1228. 'suiteName' => $allSuites[$info['testsuite_id']],
  1229. 'assigner_id' => $info['assigner_id'],
  1230. 'feature_id' => $info['feature_id'],
  1231. 'execute_link' => '');
  1232. if ($info['tcversion_id'] != $info['executed'])
  1233. {
  1234. $executionExists = false;
  1235. if (($lastResult == 'a') || ($lastResult == $this->map_tc_status['not_run']))
  1236. {
  1237. // Initialize information on testcaseID to be "not run"
  1238. // echo 'NOTRUN - DEBUG- Added Not Run info <br>';
  1239. array_push($currentSuite, $infoToSave);
  1240. }
  1241. }
  1242. if ($executionExists)
  1243. {
  1244. // TO-DO - this is where we can include the searching of results
  1245. // over multiple test plans - by modifying this select statement slightly
  1246. // to include multiple test plan ids
  1247. $sql = "SELECT * FROM {$this->tables['executions']} executions " .
  1248. "WHERE tcversion_id = " . $info['executed'] . " AND testplan_id = $this->testPlanID " .
  1249. "AND platform_id = " . $info['platform_id'];
  1250. $sql .= $sqlFilters;
  1251. // mht: fix 966
  1252. // mike_h - 20070806 - when ordering executions by the timestamp,
  1253. // the results are represented correctly in the report "Test Report".
  1254. // amitkhullar - BUGID 2156 - added option to get latest/all results in Query metrics report.
  1255. if ($all_results == 0)
  1256. {
  1257. $sql .= " ORDER BY execution_ts DESC limit 1";
  1258. }
  1259. else
  1260. {
  1261. $sql .= " ORDER BY execution_ts ASC ";
  1262. }
  1263. //echo "<br>debug - <b><i>" . __FUNCTION__ . "</i></b><br><b>" . $sql . "</b><br>";
  1264. $execQuery = $this->db->fetchArrayRowsIntoMap($sql,'id');
  1265. if ($execQuery)
  1266. {
  1267. if ($lastResult != $this->map_tc_status['not_run'])
  1268. {
  1269. foreach($execQuery as $executions_id => $execInfo)
  1270. {
  1271. $exec_row = $execInfo[0];
  1272. $infoToSave['version'] = $exec_row['tcversion_number'];
  1273. $infoToSave['build_id'] = $exec_row['build_id'];
  1274. $infoToSave['platform_id'] = $exec_row['platform_id'];
  1275. $infoToSave['tester_id'] = $exec_row['tester_id'];
  1276. $infoToSave['status'] = $exec_row['status'];
  1277. $infoToSave['notes'] = $exec_row['notes'];
  1278. $infoToSave['executions_id'] = $executions_id;
  1279. //@todo: Refactor for this code - BUGID 2242
  1280. $infoToSave['bugString'] = $searchBugs ? $this->buildBugString($this->db, $executions_id) : '';
  1281. $dummy = null;
  1282. $infoToSave['execution_ts'] = localize_dateOrTimeStamp(null, $dummy,'timestamp_format',
  1283. $exec_row['execution_ts']);
  1284. //-amitkhullar - BugID:2267
  1285. $prefixLink = '<a href="lib/execute/execSetResults.php?level=testcase&build_id=' . $infoToSave['build_id'];
  1286. // 20100518 - franciscom - BUGID 3474: Link to test case in Query Metrics Report is broken if using platforms
  1287. $prefixLink .= '&platform_id=' . $exec_row['platform_id'];
  1288. $infoToSave['execute_link'] = $prefixLink . "&id={$testcaseID}&version_id=" . $info['tcversion_id'] .
  1289. "&tplan_id=" . $this->testPlanID . '">' .
  1290. $suffixLink . $info['external_id'] . ":&nbsp;<b>" .
  1291. htmlspecialchars($info['name']). "</b></a>";
  1292. array_push($currentSuite, $infoToSave);
  1293. } // end foreach
  1294. }
  1295. } // end if($execQuery)
  1296. elseif (($lastResult == 'a') || ($lastResult == $this->map_tc_status['not_run']))
  1297. {
  1298. // HANDLE scenario where execution does not exist
  1299. array_push($currentSuite, $infoToSave);
  1300. }
  1301. } // end if($executionExists)
  1302. $executionsMap[$info['testsuite_id']] = $currentSuite;
  1303. } // foreach platform
  1304. } // end foreach
  1305. unset($infoToSave);
  1306. return $executionsMap;
  1307. } // end function
  1308. /**
  1309. * @TODO - figure out what file to include so i don't have
  1310. * to redefine this
  1311. * builds bug information for execution id
  1312. * written by Andreas, being implemented again by KL
  1313. */
  1314. function buildBugString(&$db,$execID)

Large files files are truncated, but you can click here to view the full file