PageRenderTime 62ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/functions/testplan.class.php

https://bitbucket.org/pfernandez/testlink1.9.6
PHP | 4095 lines | 2402 code | 453 blank | 1240 comment | 209 complexity | 0e0b90199993b6c3e7c62e0e24e2edc3 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. * Manages test plan operations and related items like Custom fields,
  7. * Builds, Custom fields, etc
  8. *
  9. * @package TestLink
  10. * @author franciscom
  11. * @copyright 2007-2009, TestLink community
  12. * @version CVS: $Id: testplan.class.php,v 1.209 2010/08/31 19:40:15 mx-julian Exp $
  13. * @link http://www.teamst.org/index.php
  14. *
  15. *
  16. * @internal Revisions:
  17. * 20100830 - franciscom - get_linked_tcversions() - missing cast to array $my['filters']['exec_status']
  18. * urgencyImportanceToPriorityLevel() - refactored
  19. * 20100827 - franciscom - new method wrapper - hasLinkedPlatforms()
  20. * 20100727 - asimon - BUGID 3629: modified statement in get_linked_tcversions()
  21. * 20100725 - asimon - BUGID 3497 and hopefully also 3530 fixed in unlink_tcversions()
  22. * 20100723 - asimon - commented out some old debug message in copy_linked_tcversions()
  23. * 20100722 - asimon - added missing $debugMsg to get_linked_items()
  24. * 20100721 - asimon - BUGID 3406: added user_assignments_per_build option to get_linked_tcversions()
  25. * 20100711 - franciscom - BUGID 3564 -> getPlatforms()
  26. * 20100614 - eloff - refactor getStatusTotalsByPriority() to same style as the other getStatusTotals...()
  27. * 20100610 - eloff - BUGID 3515 - getStatusTotals() now takes platforms into account
  28. * 20100602 - franciscom - copy_as() - force Platforms Link copy when user choose Test Case Copy
  29. * 20100527 - Julian - BUGID 3492 - Added execution notes to sql statement of get_linked_tcversions
  30. * 20100525 - Julian - changed default for steps_info option on get_linked_tcversions() to false
  31. * -> performance improvement because not all steps are loaded per default
  32. * 20100520 - franciscom - getTestCaseSiblings() join bug
  33. * 20100518 - franciscom - BUGID 3473
  34. * 20100516 - franciscom - BUGID 3465: Delete Test Project - User Execution Assignment is not deleted
  35. * 20100506 - franciscom - new method - get_linked_items_id(), that has perfomance advantages
  36. * over get_linked_tcversions() when only info needed is test case id.
  37. *
  38. * 20100505 - franciscom - BUGID 3434 - get_keywords_map() - refactoring trying to improve performance
  39. * 20100505 - franciscom - BUGID 3430 - copy_milestones() - need to check if start date is NOT NULL
  40. * 20100425 - franciscom - BUGID 2463 - changes in getStatusTotalsByAssignedTesterPlatform()
  41. * 20100417 - franciscom - get_linked_tcversions() added importance on output data
  42. * BUGID 3356: Failed Test Cases" report is not updated when a test case
  43. * has been changed from "Failed" to "Passed"
  44. *
  45. * 20100217 - asimon - added parameters open and active to getNumberOfBuilds()
  46. * 20100214 - franciscom - BUGID 2455, BUGID 3026 - Contribution by julian,asimon
  47. * 20100206 - eloff - BUGID 3060 - Adding getStatusTotalsByPriority()
  48. * 20100206 - eloff - BUGID 3060 - Adding urgencyImportanceToPriorityLevel() method
  49. * 20100201 - franciscom - BUGID 3121 - Adding Platform to test plan after the execution completed,
  50. * reports are not shown appropriate
  51. * 20100112 - franciscom - getPlatforms() - interface changes
  52. * 20100106 - franciscom - Multiple Test Case Steps Feature
  53. * Affected Methods: get_linked_tcversions()
  54. * 20091111 - franciscom - BUGID 2938 - getTestCaseSiblings(), getTestCaseNextSibling()
  55. * 20091031 - franciscom - tallyResultsForReport()
  56. * 20091027 - franciscom - BUGID 2500 - get_linked_tcversions()
  57. * 20091025 - franciscom - new method - getStatusTotalsByPlatform()
  58. * bug found on getNotExecutedLinkedTCVersionsDetailed()
  59. * missing testplan_id on execution join
  60. *
  61. * 20091010 - franciscom - getNotExecutedLinkedTCVersionsDetailed() new options
  62. * 20091004 - franciscom - get_linked_tcversions() - fixed query when requesting exec status filtering.
  63. * - added more columns to output record set
  64. * 20090923 - franciscom - link_tcversions() - will return data
  65. * 20090920 - franciscom - getStatusTotals(), will replace some result.class method
  66. * 20090919 - franciscom - copy_as(), copy_linked_tcversions() added contribution (refactored)
  67. * to copy user assignment.
  68. *
  69. * 20090822 - franciscom - changeLinkedTCVersionsPlatform() - new method
  70. * countLinkedTCVersionsByPlatform() - new method
  71. * 20090814 - franciscom - link_tcversions() - interface changes - due to platform feature
  72. * 20090516 - franciscom - BUGID - is_public
  73. * create(),update() changed
  74. * 20090509 - franciscom - BUGID - build class manage release_date
  75. * 20090411 - franciscom - BUGID 2369 - link_tcversions() - interface changes
  76. * 20090214 - franciscom - BUGID 2099 - get_linked_tcversions() - added new columns in output recordset
  77. * 20090208 - franciscom - testplan class - new method get_build_by_id()
  78. * 20090201 - franciscom - copy_milestones() - wrong SQL sentece
  79. * A,B,C fields renamed to lower case a,b,c to avoid problems
  80. * between differnt database (case and no case sensitive)
  81. * 20081227 - franciscom - BUGID 1913 - filter by same results on ALL previous builds
  82. * get_same_status_for_build_set(), get_prev_builds()
  83. *
  84. * 20081214 - franciscom - Thanks to postgres found missing CAST() on SUM()
  85. * 20081206 - franciscom - BUGID 1910 - get_estimated_execution_time() - added new filter
  86. * get_linked_tcversions() - added test suites filter
  87. * 20080820 - franciscom - added get_estimated_execution_time() as result of contributed idea.
  88. *
  89. * 20080811 - franciscom - BUGID 1650 (REQ)
  90. * 20080614 - franciscom - get_linked_and_newest_tcversions() - fixed bug (thanks to PostGres)
  91. * 20080428 - franciscom - supporting multiple keywords in get_linked_tcversions()
  92. * (based on contribution by Eugenia Drosdezki)
  93. * 20080310 - sbouffard - contribution added NHB.name to recordset (useful for API methods).
  94. * 20071010 - franciscom - BUGID MSSQL reserved word problem - open
  95. * 20070927 - franciscom - BUGID 1069
  96. * added _natsort_builds() (see natsort info on PHP manual).
  97. * get_builds() add call to _natsort_builds()
  98. * get_builds_for_html_options() add call to natsort()
  99. * 20070310 - franciscom - BUGID 731
  100. * 20070306 - franciscom - BUGID 705 - changes in get_linked_tcversions()
  101. **/
  102. /** related functionality */
  103. require_once( dirname(__FILE__) . '/tree.class.php' );
  104. require_once( dirname(__FILE__) . '/assignment_mgr.class.php' );
  105. require_once( dirname(__FILE__) . '/attachments.inc.php' );
  106. /**
  107. * class to coordinate and manage Test Plans
  108. * @package TestLink
  109. * @todo havlatm: create class testplanEdit (as extension of testplan class) and
  110. * move here create,edit,delete,copy related stuff
  111. * @TODO franciscom - absolutely disagree with suggested approach, see no value - 20090611
  112. */
  113. class testplan extends tlObjectWithAttachments
  114. {
  115. /** query options */
  116. const GET_ALL=null;
  117. const GET_ACTIVE_BUILD=1;
  118. const GET_INACTIVE_BUILD=0;
  119. const GET_OPEN_BUILD=1;
  120. const GET_CLOSED_BUILD=0;
  121. const ACTIVE_BUILDS=1;
  122. const ENABLED=1;
  123. /** @var database handler */
  124. var $db;
  125. var $tree_manager;
  126. var $assignment_mgr;
  127. var $cfield_mgr;
  128. var $tcase_mgr;
  129. var $assignment_types;
  130. var $assignment_status;
  131. /** message to show on GUI */
  132. var $user_feedback_message = '';
  133. var $node_types_descr_id;
  134. var $node_types_id_descr;
  135. /**
  136. * testplan class constructor
  137. *
  138. * @param resource &$db reference to database handler
  139. */
  140. function __construct(&$db)
  141. {
  142. $this->db = &$db;
  143. $this->tree_manager = New tree($this->db);
  144. $this->node_types_descr_id=$this->tree_manager->get_available_node_types();
  145. $this->node_types_id_descr=array_flip($this->node_types_descr_id);
  146. $this->assignment_mgr = new assignment_mgr($this->db);
  147. $this->assignment_types = $this->assignment_mgr->get_available_types();
  148. $this->assignment_status = $this->assignment_mgr->get_available_status();
  149. $this->cfield_mgr = new cfield_mgr($this->db);
  150. $this->tcase_mgr = New testcase($this->db);
  151. $this->platform_mgr = new tlPlatform($this->db);
  152. tlObjectWithAttachments::__construct($this->db,'testplans');
  153. }
  154. /**
  155. * creates a tesplan on Database, for a testproject.
  156. *
  157. * @param string $name: testplan name
  158. * @param string $notes: testplan notes
  159. * @param string $testproject_id: testplan parent
  160. *
  161. * @return integer status code
  162. * if everything ok -> id of new testplan (node id).
  163. * if problems -> 0.
  164. */
  165. function create($name,$notes,$testproject_id,$is_active=1,$is_public=1)
  166. {
  167. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  168. $node_types=$this->tree_manager->get_available_node_types();
  169. $tplan_id = $this->tree_manager->new_node($testproject_id,$node_types['testplan'],$name);
  170. $active_status=intval($is_active) > 0 ? 1 : 0;
  171. $public_status=intval($is_public) > 0 ? 1 : 0;
  172. $sql = "/* $debugMsg */ " .
  173. " INSERT INTO {$this->tables['testplans']} (id,notes,testproject_id,active,is_public) " .
  174. " VALUES ( {$tplan_id} " . ", '" . $this->db->prepare_string($notes) . "'," .
  175. $testproject_id . "," . $active_status . "," . $public_status . ")";
  176. $result = $this->db->exec_query($sql);
  177. $id = 0;
  178. if ($result)
  179. {
  180. $id = $tplan_id;
  181. }
  182. return $id;
  183. }
  184. /**
  185. * update testplan information
  186. *
  187. * @param integer $id Test plan identifier
  188. * @param string $name: testplan name
  189. * @param string $notes: testplan notes
  190. * @param boolean $is_active
  191. *
  192. * @return integer result code (1=ok)
  193. */
  194. function update($id,$name,$notes,$is_active=null,$is_public=null)
  195. {
  196. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  197. $do_update = 1;
  198. $result = null;
  199. // $active = to_boolean($is_active);
  200. $name = trim($name);
  201. // two tables to update and we have no transaction yet.
  202. $rsa = $this->get_by_id($id);
  203. $duplicate_check = (strcmp($rsa['name'],$name) != 0 );
  204. if($duplicate_check)
  205. {
  206. $rs = $this->get_by_name($name,$rsa['parent_id']);
  207. $do_update = is_null($rs);
  208. }
  209. if($do_update)
  210. {
  211. // Update name
  212. $sql = "/* $debugMsg */ ";
  213. $sql .= "UPDATE {$this->tables['nodes_hierarchy']} " .
  214. "SET name='" . $this->db->prepare_string($name) . "'" .
  215. "WHERE id={$id}";
  216. $result = $this->db->exec_query($sql);
  217. if($result)
  218. {
  219. $add_upd='';
  220. if( !is_null($is_active) )
  221. {
  222. $add_upd .=',active=' . (intval($is_active) > 0 ? 1 : 0);
  223. }
  224. if( !is_null($is_public) )
  225. {
  226. $add_upd .=',is_public=' . (intval($is_public) > 0 ? 1:0);
  227. }
  228. $sql = " UPDATE {$this->tables['testplans']} " .
  229. " SET notes='" . $this->db->prepare_string($notes). "' " .
  230. " {$add_upd} WHERE id=" . $id;
  231. $result = $this->db->exec_query($sql);
  232. }
  233. }
  234. return ($result ? 1 : 0);
  235. }
  236. /*
  237. function: get_by_name
  238. get information about a testplan using name as access key.
  239. Search can be narrowed, givin a testproject id as filter criteria.
  240. args: name: testplan name
  241. [tproject_id]: default:0 -> system wide search i.e. inside all testprojects
  242. returns: if nothing found -> null
  243. if found -> array where every element is a map with following keys:
  244. id: testplan id
  245. notes:
  246. active: active status
  247. is_open: open status
  248. name: testplan name
  249. testproject_id
  250. */
  251. function get_by_name($name,$tproject_id = 0)
  252. {
  253. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  254. $sql = "/* $debugMsg */ ";
  255. $sql .= " SELECT testplans.*, NH.name " .
  256. " FROM {$this->tables['testplans']} testplans, " .
  257. " {$this->tables['nodes_hierarchy']} NH" .
  258. " WHERE testplans.id=NH.id " .
  259. " AND NH.name = '" . $this->db->prepare_string($name) . "'";
  260. if($tproject_id > 0 )
  261. {
  262. $sql .= " AND NH.parent_id={$tproject_id}";
  263. }
  264. $recordset = $this->db->get_recordset($sql);
  265. return($recordset);
  266. }
  267. /*
  268. function: get_by_id
  269. args : id: testplan id
  270. returns: map with following keys:
  271. id: testplan id
  272. name: testplan name
  273. notes: testplan notes
  274. testproject_id
  275. active
  276. is_open
  277. parent_id
  278. */
  279. function get_by_id($id)
  280. {
  281. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  282. $sql = "/* $debugMsg */ " .
  283. " SELECT testplans.*,NH.name,NH.parent_id " .
  284. " FROM {$this->tables['testplans']} testplans, " .
  285. " {$this->tables['nodes_hierarchy']} NH " .
  286. " WHERE testplans.id = NH.id AND testplans.id = {$id}";
  287. $recordset = $this->db->get_recordset($sql);
  288. return($recordset ? $recordset[0] : null);
  289. }
  290. /*
  291. function: get_all
  292. get array of info for every test plan,
  293. without considering Test Project and any other kind of filter.
  294. Every array element contains an assoc array
  295. args : -
  296. returns: array, every element is a map with following keys:
  297. id: testplan id
  298. name: testplan name
  299. notes: testplan notes
  300. testproject_id
  301. active
  302. is_open
  303. parent_id
  304. */
  305. function get_all()
  306. {
  307. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  308. $sql = "/* $debugMsg */ " .
  309. " SELECT testplans.*, NH.name " .
  310. " FROM {$this->tables['testplans']} testplans, " .
  311. " {$this->tables['nodes_hierarchy']} NH " .
  312. " WHERE testplans.id=NH.id";
  313. $recordset = $this->db->get_recordset($sql);
  314. return $recordset;
  315. }
  316. /*
  317. function: count_testcases
  318. get number of testcases linked to a testplan
  319. args: id: testplan id
  320. [platform_id]: null => do not filter by platform
  321. returns: number
  322. */
  323. public function count_testcases($id,$platform_id=null)
  324. {
  325. $sql_filter = '';
  326. if( !is_null($platform_id) )
  327. {
  328. $sql_filter = " AND platform_id={$platform_id} ";
  329. }
  330. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  331. $sql = "/* $debugMsg */ " .
  332. " SELECT COUNT(testplan_id) AS qty " .
  333. " FROM {$this->tables['testplan_tcversions']} " .
  334. " WHERE testplan_id={$id} {$sql_filter}";
  335. $recordset = $this->db->get_recordset($sql);
  336. $qty = 0;
  337. if(!is_null($recordset))
  338. {
  339. $qty = $recordset[0]['qty'];
  340. }
  341. return $qty;
  342. }
  343. /*
  344. function: tcversionInfoForAudit
  345. get info regarding tcversions, to generate useful audit messages
  346. args :
  347. $tplan_id: test plan id
  348. $items_to_link: map key=tc_id
  349. value: tcversion_id
  350. returns: -
  351. rev: 20080629 - franciscom - audit message improvements
  352. */
  353. function tcversionInfoForAudit($tplan_id,&$items)
  354. {
  355. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  356. // Get human readeable info for audit
  357. $ret=array();
  358. $tcase_cfg = config_get('testcase_cfg');
  359. $dummy=reset($items);
  360. list($ret['tcasePrefix'],$tproject_id) = $this->tcase_mgr->getPrefix($dummy);
  361. $ret['tcasePrefix'] .= $tcase_cfg->glue_character;
  362. $sql = "/* $debugMsg */ " .
  363. " SELECT TCV.id, tc_external_id, version, NHB.name " .
  364. " FROM {$this->tables['tcversions']} TCV,{$this->tables['nodes_hierarchy']} NHA, " .
  365. " {$this->tables['nodes_hierarchy']} NHB " .
  366. " WHERE NHA.id=TCV.id " .
  367. " AND NHB.id=NHA.parent_id " .
  368. " AND TCV.id IN (" . implode(',',$items) . ")";
  369. $ret['info']=$this->db->fetchRowsIntoMap($sql,'id');
  370. $ret['tplanInfo']=$this->get_by_id($tplan_id);
  371. return $ret;
  372. }
  373. /**
  374. * associates version of different test cases to a test plan.
  375. * this is the way to populate a test plan
  376. args :
  377. $id: test plan id
  378. $items_to_link: map key=tc_id
  379. value= map with
  380. key: platform_id (can be 0)
  381. value: tcversion_id
  382. passed by reference for speed
  383. returns: -
  384. rev: 20080629 - franciscom - audit message improvements
  385. */
  386. function link_tcversions($id,&$items_to_link,$userId)
  387. {
  388. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  389. // Get human readeable info for audit
  390. $title_separator = config_get('gui_title_separator_1');
  391. $auditInfo=$this->tcversionInfoForAudit($id,$items_to_link['tcversion']);
  392. $platformInfo = $this->platform_mgr->getLinkedToTestplanAsMap($id);
  393. $platformLabel = lang_get('platform');
  394. // Important: MySQL do not support default values on datetime columns that are functions
  395. // that's why we are using db_now().
  396. $sql = "/* $debugMsg */ " .
  397. "INSERT INTO {$this->tables['testplan_tcversions']} " .
  398. "(testplan_id,author_id,creation_ts,tcversion_id,platform_id) " .
  399. " VALUES ({$id},{$userId},{$this->db->db_now()},";
  400. $features=null;
  401. foreach($items_to_link['items'] as $tcase_id => $items)
  402. {
  403. foreach($items as $platform_id => $tcversion)
  404. {
  405. $addInfo='';
  406. $result = $this->db->exec_query($sql . "{$tcversion}, {$platform_id})");
  407. if ($result)
  408. {
  409. $features[$platform_id][$tcversion]=$this->db->insert_id($this->tables['testplan_tcversions']);
  410. if( isset($platformInfo[$platform_id]) )
  411. {
  412. $addInfo = ' - ' . $platformLabel . ':' . $platformInfo[$platform_id];
  413. }
  414. $auditMsg=TLS("audit_tc_added_to_testplan",
  415. $auditInfo['tcasePrefix'] . $auditInfo['info'][$tcversion]['tc_external_id'] .
  416. $title_separator . $auditInfo['info'][$tcversion]['name'],
  417. $auditInfo['info'][$tcversion]['version'],
  418. $auditInfo['tplanInfo']['name'] . $addInfo );
  419. logAuditEvent($auditMsg,"ASSIGN",$id,"testplans");
  420. }
  421. }
  422. }
  423. return $features;
  424. }
  425. /*
  426. function: setExecutionOrder
  427. args :
  428. $id: test plan id
  429. $executionOrder: assoc array key=tcversion_id value=order
  430. passed by reference for speed
  431. returns: -
  432. */
  433. function setExecutionOrder($id,&$executionOrder)
  434. {
  435. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  436. foreach($executionOrder as $tcVersionID => $execOrder)
  437. {
  438. $execOrder=intval($execOrder);
  439. $sql="/* $debugMsg */ UPDATE {$this->tables['testplan_tcversions']} " .
  440. "SET node_order={$execOrder} " .
  441. "WHERE testplan_id={$id} " .
  442. "AND tcversion_id={$tcVersionID}";
  443. $result = $this->db->exec_query($sql);
  444. }
  445. }
  446. /**
  447. *
  448. * @internal revisions:
  449. * 20100722 - asimon - added missing $debugMsg
  450. */
  451. function get_linked_items_id($id)
  452. {
  453. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  454. $sql = " /* $debugMsg */ ".
  455. " SELECT DISTINCT parent_id FROM {$this->tables['nodes_hierarchy']} NHTC " .
  456. " JOIN {$this->tables['testplan_tcversions']} TPTCV ON TPTCV.tcversion_id = NHTC.id " .
  457. " WHERE TPTCV.testplan_id = {$id} ";
  458. $linked_items = $this->db->fetchRowsIntoMap($sql,'parent_id');
  459. return $linked_items;
  460. }
  461. /*
  462. function: get_linked_tcversions
  463. get information about testcases linked to a testplan.
  464. args :
  465. id: testplan id
  466. [filters]: map with following keys
  467. [tcase_id]: default null => get any testcase
  468. numeric => just get info for this testcase
  469. [keyword_id]: default 0 => do not filter by keyword id
  470. numeric => filter by keyword id
  471. [assigned_to]: default NULL => do not filter by user assign.
  472. array() with user id to be used on filter
  473. [exec_status]: default NULL => do not filter by execution status
  474. character or array => filter by execution status=character
  475. [build_id]: default 0 => do not filter by build id
  476. numeric => filter by build id
  477. [cf_hash]: default null => do not filter by Custom Fields values
  478. [urgencyImportance] : filter only Tc's with certain (urgency*importance)-value
  479. [tsuites_id]: default null.
  480. If present only tcversions that are children of this testsuites
  481. will be included
  482. [exec_type] default null -> all types.
  483. [platform_id]
  484. [options]: map with following keys
  485. [output]: controls data type returned
  486. default: map -> map indexed by test case id (original return type)
  487. Using this option is (in a certain way) as having
  488. added DISTINCT on SQL clause.
  489. YOU WILL GET ONLY LAST EXECUTION (means one record)
  490. of each test case.
  491. mapOfMap: first key testcase_id, second key platform_id
  492. You GET ONLY LAST EXECUTION (means one record)
  493. of each test case.
  494. mapOfArray -> indexed by test case id but with an array
  495. where each element contains information
  496. according to Platform.
  497. Be carefull if you have multiple executions
  498. for same (testcase,platform) YOU WILL GET
  499. MULTIPLE ELEMENTS IN ARRAY
  500. array -> indexed sequentially.
  501. [only_executed]: default false => get executed and NOT executed
  502. get only executed tcversions
  503. [execution_details]: default NULL => by platftorm
  504. add_build => by build AND platform
  505. [last_execution]: default false => return all executions
  506. true => last execution ( MAX(E.id))
  507. [include_unassigned]: has effects only if [assigned_to] <> null.
  508. default: false
  509. true: also testcase not assigned will be retreived
  510. [details]: controls columns returned
  511. default 'simple'
  512. 'full': add summary, steps and expected_results, and test suite name
  513. 'summary': add summary
  514. [steps_info]: controls if step info has to be added on output
  515. default true
  516. [user_assignments_per_build]: contains a build ID, for which the
  517. assigned user shall get loaded
  518. returns: changes according options['output'] (see above)
  519. Notice:
  520. executed field: will take the following values
  521. - NULL if the tc version has not been executed in THIS test plan.
  522. - tcversion_id if has executions.
  523. rev :
  524. 20100727 - asimon - BUGID 3629: modified statement
  525. 20100721 - asimon - BUGID 3406: added user_assignments_per_build option
  526. 20100520 - franciscom - added option steps_info, to try to solve perfomance problems
  527. allowing caller to ask for NO INFO ABOUT STEPS
  528. 20100417 - franciscom - added importance on output data
  529. BUGID 3356: "Failed Test Cases" report is not updated when a test case
  530. has been changed from "Failed" to "Passed"
  531. 20090814 - franciscom - interface changes due to platform feature
  532. */
  533. public function get_linked_tcversions($id,$filters=null,$options=null)
  534. {
  535. $debugMsg = 'Class: ' . __CLASS__ . ' - Method:' . __FUNCTION__;
  536. $my = array ('filters' => '', 'options' => '');
  537. $tcversion_exec_type = array('join' => '', 'filter' => '');
  538. $tc_id = array('join' => '', 'filter' => '');
  539. $builds = array('join' => '', 'filter' => '');
  540. $keywords = array('join' => '', 'filter' => '');
  541. $executions = array('join' => '', 'filter' => '');
  542. $platforms = array('join' => '', 'filter' => '');
  543. $my['filters'] = array('tcase_id' => null, 'keyword_id' => 0,
  544. 'assigned_to' => null, 'exec_status' => null,
  545. 'build_id' => 0, 'cf_hash' => null,
  546. 'urgencyImportance' => null, 'tsuites_id' => null,
  547. 'platform_id' => null, 'exec_type' => null);
  548. $my['options'] = array('only_executed' => false, 'include_unassigned' => false,
  549. 'output' => 'map', 'details' => 'simple', 'steps_info' => false,
  550. 'execution_details' => null, 'last_execution' => false);
  551. // Cast to array to handle $options = null
  552. $my['filters'] = array_merge($my['filters'], (array)$filters);
  553. $my['options'] = array_merge($my['options'], (array)$options);
  554. // 20100830 - franciscom - bug found by Julian
  555. $my['filters']['exec_status'] = (array)$my['filters']['exec_status'];
  556. // new dBug($my['filters']);
  557. // new dBug($my['options']);
  558. $groupByPlatform=($my['options']['output']=='mapOfMap' ||
  559. $my['options']['output']=='mapOfMapExecPlatform') ? ',platform_id' : '';
  560. $groupByBuild=($my['options']['execution_details'] == 'add_build') ? ',build_id' : '';
  561. // BUGID 3406: user assignments per build
  562. $ua_build = isset($my['options']['user_assignments_per_build']) ?
  563. $my['options']['user_assignments_per_build'] : 0;
  564. // BUGID 3629
  565. $ua_build_sql = $ua_build && is_numeric($ua_build) ? " AND UA.build_id={$ua_build} " : " ";
  566. // @TODO - 20091004 - franciscom
  567. // Think that this subquery in not good when we add execution filter
  568. // $last_exec_subquery = " AND E.id IN ( SELECT MAX(id) " .
  569. // " FROM {$this->tables['executions']} executions " .
  570. // " WHERE testplan_id={$id} %EXECSTATUSFILTER%" .
  571. // " GROUP BY tcversion_id,testplan_id {$groupByPlatform} {$groupByBuild} )";
  572. // I've had confirmation of BAD query;
  573. // BUGID 3356: "Failed Test Cases" report is not updated when a test case
  574. // has been changed from "Failed" to "Passed"
  575. //
  576. // SUBQUERY CAN NOT HAVE ANY KIND OF FILTERING other that test plan.
  577. // Adding exec status, means that we will get last exec WITH THIS STATUS, and not THE LATEST EXEC
  578. $last_exec_subquery = " AND E.id IN ( SELECT MAX(id) " .
  579. " FROM {$this->tables['executions']} executions " .
  580. " WHERE testplan_id={$id} " .
  581. " GROUP BY tcversion_id,testplan_id {$groupByPlatform} {$groupByBuild} )";
  582. $resultsCfg = config_get('results');
  583. $status_not_run=$resultsCfg['status_code']['not_run'];
  584. $sql_subquery='';
  585. // franciscom
  586. // WARNING:
  587. // Order of analisys seems to be critic, because $executions['filter'] is overwritten
  588. // on some situation below if filtering on execution status is requested
  589. if( $my['options']['last_execution'] )
  590. {
  591. $executions['filter'] = " {$last_exec_subquery} ";
  592. // 20100417 - franciscom - BUGID 3356
  593. // $executions['filter'] = str_ireplace("%EXECSTATUSFILTER%", "", $executions['filter']);
  594. }
  595. if( !is_null($my['filters']['platform_id']) )
  596. {
  597. $platforms['filter'] = " AND T.platform_id = {$my['filters']['platform_id']} ";
  598. }
  599. // 20100417- Why to use a list ? - must be checked if is on
  600. if( !is_null($my['filters']['exec_type']) )
  601. {
  602. $tcversion_exec_type['filter'] = "AND TCV.execution_type IN (" .
  603. implode(",",(array)$my['filters']['exec_type']) . " ) ";
  604. }
  605. // Based on work by Eugenia Drosdezki
  606. if( is_array($my['filters']['keyword_id']) )
  607. {
  608. // 0 -> no keyword, remove
  609. if( $my['filters']['keyword_id'][0] == 0 )
  610. {
  611. array_shift($my['filters']['keyword_id']);
  612. }
  613. if(count($my['filters']['keyword_id']))
  614. {
  615. $keywords['filter'] = " AND TK.keyword_id IN (" . implode(',',$my['filters']['keyword_id']) . ")";
  616. }
  617. }
  618. else if($my['filters']['keyword_id'] > 0)
  619. {
  620. $keywords['filter'] = " AND TK.keyword_id = {$my['filters']['keyword_id']} ";
  621. }
  622. if(trim($keywords['filter']) != "")
  623. {
  624. $keywords['join'] = " JOIN {$this->tables['testcase_keywords']} TK ON NHA.parent_id = TK.testcase_id ";
  625. }
  626. if (!is_null($my['filters']['tcase_id']) )
  627. {
  628. if( is_array($my['filters']['tcase_id']) )
  629. {
  630. $tc_id['filter'] = " AND NHA.parent_id IN (" . implode(',',$my['filters']['tcase_id']) . ")";
  631. }
  632. else if ($my['filters']['tcase_id'] > 0 )
  633. {
  634. $tc_id['filter'] = " AND NHA.parent_id = {$my['filters']['tcase_id']} ";
  635. }
  636. }
  637. // --------------------------------------------------------------
  638. if(!is_null($my['filters']['exec_status']) )
  639. {
  640. $executions['filter'] = '';
  641. $notrun['filter'] = null;
  642. $otherexec['filter'] = null;
  643. $notRunPresent = array_search($status_not_run,$my['filters']['exec_status']);
  644. if($notRunPresent !== false)
  645. {
  646. $notrun['filter'] = " E.status IS NULL ";
  647. unset($my['filters']['exec_status'][$notRunPresent]);
  648. }
  649. if(count($my['filters']['exec_status']) > 0)
  650. {
  651. $otherexec['filter']=" E.status IN ('" . implode("','",$my['filters']['exec_status']) . "') ";
  652. // 20100417 - franciscom - BUGID 3356
  653. // $status_filter=str_ireplace("E.", "executions.", $otherexec['filter']);
  654. // $sql_subquery = str_ireplace("%EXECSTATUSFILTER%", "AND {$status_filter}", $last_exec_subquery);
  655. // code commented before BUGID 3356
  656. // $sql_subquery = str_ireplace("E.", "executions.", $sql_subquery);
  657. // $sql_subquery = $last_exec_subquery;
  658. // 20100417 - franciscom - BUGID 3356
  659. // $executions['filter'] = " ( {$otherexec['filter']} {$sql_subquery} ) ";
  660. $executions['filter'] = " ( {$otherexec['filter']} {$last_exec_subquery} ) ";
  661. }
  662. if( !is_null($notrun['filter']) )
  663. {
  664. if($executions['filter'] != "")
  665. {
  666. $executions['filter'] .= " OR ";
  667. }
  668. $executions['filter'] .= $notrun['filter'];
  669. }
  670. if($executions['filter'] != "")
  671. {
  672. // Just add the AND
  673. $executions['filter'] = " AND ({$executions['filter']} )";
  674. }
  675. }
  676. // --------------------------------------------------------------
  677. if( $my['filters']['build_id'] > 0 )
  678. {
  679. $builds['filter'] = " AND E.build_id={$my['filters']['build_id']} ";
  680. }
  681. // there are several situation where you need to use LEFT OUTER
  682. if(!$my['options']['only_executed'])
  683. {
  684. $executions['join'] = " LEFT OUTER ";
  685. }
  686. // platform feature
  687. $executions['join'] .= " JOIN {$this->tables['executions']} E ON " .
  688. " (NHA.id = E.tcversion_id AND " .
  689. " E.platform_id=T.platform_id AND " .
  690. " E.testplan_id=T.testplan_id {$builds['filter']}) ";
  691. // --------------------------------------------------------------
  692. $more_tcase_fields = '';
  693. $join_for_parent = '';
  694. $more_parent_fields = '';
  695. $more_exec_fields='';
  696. switch($my['options']['details'])
  697. {
  698. case 'full':
  699. $more_tcase_fields .= 'TCV.summary,';
  700. $join_for_parent .= " JOIN {$this->tables['nodes_hierarchy']} NHC ON NHB.parent_id = NHC.id ";
  701. $more_parent_fields .= 'NHC.name as tsuite_name,';
  702. break;
  703. case 'summary':
  704. $more_tcase_fields .= 'TCV.summary,';
  705. break;
  706. }
  707. if($my['options']['execution_details'] == 'add_build')
  708. {
  709. $more_exec_fields .= 'E.build_id,B.name AS build_name,';
  710. $builds['join']=" LEFT OUTER JOIN {$this->tables['builds']} B ON B.id=E.build_id ";
  711. }
  712. // BUGID 3406 - assignments per build
  713. // BUGID 3492 - Added execution notes to sql statement of get_linked_tcversions
  714. $sql = "/* $debugMsg */ " .
  715. " SELECT NHB.parent_id AS testsuite_id, {$more_tcase_fields} {$more_parent_fields}" .
  716. " NHA.parent_id AS tc_id, NHB.node_order AS z, NHB.name," .
  717. " T.platform_id, PLAT.name as platform_name ,T.id AS feature_id, T.tcversion_id AS tcversion_id, " .
  718. " T.node_order AS execution_order, T.creation_ts AS linked_ts, T.author_id AS linked_by," .
  719. " TCV.version AS version, TCV.active," .
  720. " TCV.tc_external_id AS external_id, TCV.execution_type,TCV.importance," .
  721. " E.id AS exec_id, E.tcversion_number," .
  722. " E.tcversion_id AS executed, E.testplan_id AS exec_on_tplan, {$more_exec_fields}" .
  723. " E.execution_type AS execution_run_type, E.testplan_id AS exec_on_tplan, " .
  724. " E.execution_ts, E.tester_id, E.notes as execution_notes, ".
  725. " UA.build_id as assigned_build_id, " . // 3406
  726. " UA.user_id,UA.type,UA.status,UA.assigner_id,T.urgency, " .
  727. " COALESCE(E.status,'" . $status_not_run . "') AS exec_status, ".
  728. " (urgency * importance) AS priority " .
  729. " FROM {$this->tables['nodes_hierarchy']} NHA " .
  730. " JOIN {$this->tables['nodes_hierarchy']} NHB ON NHA.parent_id = NHB.id " .
  731. $join_for_parent .
  732. " JOIN {$this->tables['testplan_tcversions']} T ON NHA.id = T.tcversion_id " .
  733. " JOIN {$this->tables['tcversions']} TCV ON NHA.id = TCV.id {$tcversion_exec_type['filter']} " .
  734. " {$executions['join']} " .
  735. " {$keywords['join']} " .
  736. " {$builds['join']} " .
  737. " LEFT OUTER JOIN {$this->tables['platforms']} PLAT ON PLAT.id = T.platform_id " .
  738. " LEFT OUTER JOIN {$this->tables['user_assignments']} UA ON UA.feature_id = T.id " .
  739. " {$ua_build_sql} " . // 3406
  740. " WHERE T.testplan_id={$id} {$keywords['filter']} {$tc_id['filter']} {$platforms['filter']}" .
  741. " AND (UA.type={$this->assignment_types['testcase_execution']['id']} OR UA.type IS NULL) " .
  742. $executions['filter'];
  743. // 20081220 - franciscom
  744. // if (!is_null($assigned_to) && $assigned_to > 0)
  745. // {
  746. //
  747. // If special user id TL_USER_ANYBODY is present in set of user id,
  748. // we will DO NOT FILTER by user ID
  749. if( !is_null($my['filters']['assigned_to']) &&
  750. !in_array(TL_USER_ANYBODY,(array)$my['filters']['assigned_to']) )
  751. {
  752. $sql .= " AND ";
  753. // Warning!!!:
  754. // If special user id TL_USER_NOBODY is present in set of user id
  755. // we will ignore any other user id present on set.
  756. if( in_array(TL_USER_NOBODY,(array)$my['filters']['assigned_to']) )
  757. {
  758. $sql .= " UA.user_id IS NULL ";
  759. }
  760. // BUGID 2455
  761. // new user filter "somebody" --> all asigned testcases
  762. else if( in_array(TL_USER_SOMEBODY,(array)$my['filters']['assigned_to']) )
  763. {
  764. $sql .= " UA.user_id IS NOT NULL ";
  765. }
  766. else
  767. {
  768. $sql_unassigned="";
  769. if( $my['options']['include_unassigned'] )
  770. {
  771. $sql .= "(";
  772. $sql_unassigned=" OR UA.user_id IS NULL)";
  773. }
  774. // BUGID 2500
  775. $sql .= " UA.user_id IN (" . implode(",",(array)$my['filters']['assigned_to']) . ") " . $sql_unassigned;
  776. }
  777. }
  778. if (!is_null($my['filters']['urgencyImportance']))
  779. {
  780. $urgencyImportanceCfg = config_get("urgencyImportance");
  781. if ($my['filters']['urgencyImportance'] == HIGH)
  782. {
  783. $sql .= " AND (urgency * importance) >= " . $urgencyImportanceCfg->threshold['high'];
  784. }
  785. else if($my['filters']['urgencyImportance'] == LOW)
  786. {
  787. $sql .= " AND (urgency * importance) < " . $urgencyImportanceCfg->threshold['low'];
  788. }
  789. else
  790. {
  791. $sql .= " AND ( ((urgency * importance) >= " . $urgencyImportanceCfg->threshold['low'] .
  792. " AND ((urgency * importance) < " . $urgencyImportanceCfg->threshold['high']."))) ";
  793. }
  794. }
  795. // test suites filter
  796. if (!is_null($my['filters']['tsuites_id']))
  797. {
  798. $tsuiteSet = is_array($my['filters']['tsuites_id']) ? $my['filters']['tsuites_id'] : array($my['filters']['tsuites_id']);
  799. $sql .= " AND NHB.parent_id IN (" . implode(',',$tsuiteSet) . ")";
  800. }
  801. $sql .= " ORDER BY testsuite_id,NHB.node_order,tc_id,platform_id,E.id ASC";
  802. switch($my['options']['output'])
  803. {
  804. case 'array':
  805. $recordset = $this->db->get_recordset($sql);
  806. break;
  807. case 'mapOfArray':
  808. $recordset = $this->db->fetchRowsIntoMap($sql,'tc_id',database::CUMULATIVE);
  809. break;
  810. case 'mapOfMap':
  811. // with this option we got just one record for each (testcase,platform)
  812. // no matter how many executions has been done
  813. $recordset = $this->db->fetchMapRowsIntoMap($sql,'tc_id','platform_id');
  814. break;
  815. case 'mapOfMapExecPlatform':
  816. // with this option we got just one record for each (platform, build)
  817. $recordset = $this->db->fetchMapRowsIntoMap($sql,'exec_id','platform_id');
  818. break;
  819. case 'map':
  820. default:
  821. $recordset = $this->db->fetchRowsIntoMap($sql,'tc_id');
  822. // 20070913 - jbarchibald
  823. // here we add functionality to filter out the custom field selections
  824. //
  825. // After addition of platform feature, this filtering can not be done
  826. // always with original filter_cf_selection().
  827. // Fisrt choice:
  828. // Enable this feature only if recordset maintains original structured
  829. //
  830. if (!is_null($my['filters']['cf_hash'])) {
  831. $recordset = $this->filter_cf_selection($recordset, $my['filters']['cf_hash']);
  832. }
  833. break;
  834. }
  835. // Multiple Test Case Steps Feature
  836. // added after Julian mail regarding perf problems building exec tree
  837. if( !is_null($recordset) && $my['options']['steps_info'])
  838. {
  839. $itemSet = array_keys($recordset);
  840. switch($my['options']['output'])
  841. {
  842. case 'mapOfArray':
  843. case 'mapOfMap':
  844. foreach($itemSet as $itemKey)
  845. {
  846. $keySet = array_keys($recordset[$itemKey]);
  847. $target = &$recordset[$itemKey];
  848. foreach($keySet as $accessKey)
  849. {
  850. $step_set = $this->tcase_mgr->get_steps($target[$accessKey]['tcversion_id']);
  851. $target[$accessKey]['steps'] = $step_set;
  852. }
  853. }
  854. break;
  855. case 'array':
  856. case 'map':
  857. default:
  858. foreach($itemSet as $accessKey)
  859. {
  860. $step_set = $this->tcase_mgr->get_steps($recordset[$accessKey]['tcversion_id']);
  861. $recordset[$accessKey]['steps'] = $step_set;
  862. }
  863. break;
  864. }
  865. }
  866. return $recordset;
  867. }
  868. /*
  869. function: get_linked_and_newest_tcversions
  870. returns for every test case in a test plan
  871. the tc version linked and the newest available version
  872. args: id: testplan id
  873. [tcase_id]: default null => all testcases linked to testplan
  874. returns: map key: testcase internal id
  875. values: map with following keys:
  876. [name]
  877. [tc_id] (internal id)
  878. [tcversion_id]
  879. [newest_tcversion_id]
  880. [tc_external_id]
  881. [version] (for humans)
  882. [newest_version] (for humans)
  883. rev:
  884. 20080614 - franciscom - fixed bug on SQL generated while
  885. adding tc_external_id on results.
  886. 20080126 - franciscom - added tc_external_id on results
  887. */
  888. function get_linked_and_newest_tcversions($id,$tcase_id=null)
  889. {
  890. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  891. $tc_id_filter = " ";
  892. if (!is_null($tcase_id) )
  893. {
  894. if( is_array($tcase_id) )
  895. {
  896. // ??? implement as in ?
  897. }
  898. else if ($tcase_id > 0 )
  899. {
  900. $tc_id_filter = " AND NHA.parent_id = {$tcase_id} ";
  901. }
  902. }
  903. // 20080614 - franciscom
  904. // Peter Rooms found bug due to wrong SQL, accepted by MySQL but not by PostGres
  905. // Missing column in GROUP BY Clause
  906. $sql = " SELECT MAX(NHB.id) AS newest_tcversion_id, " .
  907. " NHA.parent_id AS tc_id, NHC.name, T.tcversion_id AS tcversion_id," .
  908. " TCVA.tc_external_id AS tc_external_id, TCVA.version AS version " .
  909. " FROM {$this->tables['nodes_hierarchy']} NHA " .
  910. // NHA - will contain ONLY nodes of type testcase_version that are LINKED to test plan
  911. " JOIN {$this->tables['testplan_tcversions']} T ON NHA.id = T.tcversion_id " .
  912. // Get testcase_version data for LINKED VERSIONS
  913. " JOIN {$this->tables['tcversions']} TCVA ON TCVA.id = T.tcversion_id" .
  914. // Work on Sibblings - Start
  915. // NHB - Needed to get ALL testcase_version sibblings nodes
  916. " JOIN {$this->tables['nodes_hierarchy']} NHB ON NHB.parent_id = NHA.parent_id " .
  917. // Want only ACTIVE Sibblings
  918. " JOIN {$this->tables['tcversions']} TCVB ON TCVB.id = NHB.id AND TCVB.active=1 " .
  919. // Work on Sibblings - STOP
  920. // NHC will contain - nodes of type TESTCASE (parent of testcase versions we are working on)
  921. // we use NHC to get testcase NAME ( testcase version nodes have EMPTY NAME)
  922. " JOIN {$this->tables['nodes_hierarchy']} NHC ON NHC.id = NHA.parent_id " .
  923. // Want to get only testcase version with id (NHB.id) greater than linked one (NHA.id)
  924. " WHERE T.testplan_id={$id} AND NHB.id > NHA.id" . $tc_id_filter .
  925. " GROUP BY NHA.parent_id, NHC.name, T.tcversion_id, TCVA.tc_external_id, TCVA.version ";
  926. $sql2 = " SELECT SUBQ.name, SUBQ.newest_tcversion_id, SUBQ.tc_id, " .
  927. " SUBQ.tcversion_id, SUBQ.version, SUBQ.tc_external_id, " .
  928. " TCV.version AS newest_version " .
  929. " FROM {$this->tables['tcversions']} TCV, ( $sql ) AS SUBQ " .
  930. " WHERE SUBQ.newest_tcversion_id = TCV.id " .
  931. " ORDER BY SUBQ.tc_id ";
  932. return $this->db->fetchRowsIntoMap($sql2,'tc_id');
  933. }
  934. /**
  935. * Remove of records from user_assignments table
  936. * @author franciscom
  937. *
  938. * @param integer $id : test plan id
  939. * @param array $items: assoc array key=tc_id value=tcversion_id
  940. *
  941. * @internal revisions:
  942. * 20100725 - asimon - BUGID 3497 and hopefully also 3530
  943. */
  944. function unlink_tcversions($id,&$items)
  945. {
  946. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  947. if(is_null($items))
  948. {
  949. return;
  950. }
  951. // Get human readeable info for audit
  952. $gui_cfg = config_get('gui');
  953. $title_separator = config_get('gui_title_separator_1');
  954. $auditInfo=$this->tcversionInfoForAudit($id,$items['tcversion']);
  955. $platformInfo = $this->platform_mgr->getLinkedToTestplanAsMap($id);
  956. $platformLabel = lang_get('platform');
  957. $dummy = null;
  958. foreach($items['items'] as $tcase_id => $elem)
  959. {
  960. foreach($elem as $platform_id => $tcversion_id)
  961. {
  962. $dummy[] = "(tcversion_id = {$tcversion_id} AND platform_id = {$platform_id})";
  963. }
  964. }
  965. $where_clause = implode(" OR ", $dummy);
  966. /*
  967. * asimon - BUGID 3497 and hopefully also 3530
  968. * A very litte error, missing braces in the $where_clause, was causing this bug.
  969. * When one set of testcases is linked to two testplans, this statement should check
  970. * that the combination of testplan_id, tcversion_id and platform_id was the same,
  971. * but instead it checked for either testplan_id OR tcversion_id and platform_id.
  972. * So every linked testcase with fitting tcversion_id and platform_id without execution
  973. * was deleted, regardless of testplan_id.
  974. * Simply adding braces around the where clause solves this.
  975. * So innstead of:
  976. * SELECT id AS link_id FROM testplan_tcversions
  977. * WHERE testplan_id=12 AND (tcversion_id = 5 AND platform_id = 0)
  978. * OR (tcversion_id = 7 AND platform_id = 0)
  979. * OR (tcversion_id = 9 AND platform_id = 0)
  980. * OR (tcversion_id = 11 AND platform_id = 0)
  981. * we need this:
  982. * SELECT ... WHERE testplan_id=12 AND (... OR ...)
  983. */
  984. $where_clause = " ( {$where_clause} ) ";
  985. // First get the executions id if any exist
  986. $sql=" SELECT id AS execution_id " .
  987. " FROM {$this->tables['executions']} " .
  988. " WHERE testplan_id = {$id} AND ${where_clause}";
  989. $exec_ids = $this->db->fetchRowsIntoMap($sql,'execution_id');
  990. if( !is_null($exec_ids) and count($exec_ids) > 0 )
  991. {
  992. // has executions
  993. $exec_ids = array_keys($exec_ids);
  994. $exec_id_where= " WHERE execution_id IN (" . implode(",",$exec_ids) . ")";
  995. // Remove bugs if any exist
  996. $sql=" DELETE FROM {$this->tables['execution_bugs']} {$exec_id_where} ";
  997. $result = $this->db->exec_query($sql);
  998. // now remove executions
  999. $sql=" DELETE FROM {$this->tables['executions']} " .
  1000. " WHERE testplan_id = {$id} AND ${where_clause}";
  1001. $result = $this->db->exec_query($sql);
  1002. }
  1003. // ----------------------------------------------------------------
  1004. // to remove the assignment to users (if any exists) we need the list of id
  1005. $sql=" SELECT id AS link_id FROM {$this->tables['testplan_tcversions']} " .
  1006. " WHERE testplan_id={$id} AND {$where_clause} ";
  1007. $link_ids = $this->db->fetchRowsIntoMap($sql,'link_id');
  1008. $features = array_keys($link_ids);
  1009. if( count($features) == 1)
  1010. {
  1011. $features=$features[0];
  1012. }
  1013. $this->assignment_mgr->delete_by_feature_id($features);
  1014. // ----------------------------------------------------------------
  1015. // Delete from link table
  1016. $sql=" DELETE FROM {$this->tables['testplan_tcversions']} " .
  1017. " WHERE testplan_id={$id} AND {$where_clause} ";
  1018. $result = $this->db->exec_query($sql);
  1019. foreach($items['items'] as $tcase_id => $elem)
  1020. {
  1021. foreach($elem as $platform_id => $tcversion)
  1022. {
  1023. $addInfo='';
  1024. if( isset($platformInfo[$platform_id]) )
  1025. {
  1026. $addInfo = ' - ' . $platformLabel . ':' . $platformInfo[$platform_id];
  1027. }
  1028. $auditMsg=TLS("audit_tc_removed_from_testplan",
  1029. $auditInfo['tcasePrefix'] . $auditInfo['info'][$tcversion]['tc_external_id'] .
  1030. $title_separator . $auditInfo['info'][$tcversion]['name'],
  1031. $auditInfo['info'][$tcversion]['version'],
  1032. $auditInfo['tplanInfo']['name'] . $addInfo );
  1033. logAuditEvent($auditMsg,"UNASSIGN",$id,"testplans");
  1034. }
  1035. }
  1036. } // end function unlink_tcversions
  1037. /**
  1038. *
  1039. * @internal revisions
  1040. * 20100505 - franciscom - BUGID 3434
  1041. */
  1042. function get_keywords_map($id,$order_by_clause='')
  1043. {
  1044. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  1045. $map_keywords=null;
  1046. // keywords are associated to testcase id, then first
  1047. // we need to get the list of testcases linked to the testplan
  1048. //
  1049. // 20100505 - according to user report (BUGID 3434) seems that
  1050. // $linked_items = $this->get_linked_tcversions($id);
  1051. // has performance problems.
  1052. // Then make a choice do simple query here.
  1053. //
  1054. $sql = " /* $debugMsg */ ".
  1055. " SELECT DISTINCT parent_id FROM {$this->tables['nodes_hierarchy']} NHTC " .
  1056. " JOIN {$this->tables['testplan_tcversions']} TPTCV ON TPTCV.tcversion_id = NHTC.id " .
  1057. " WHERE TPTCV.testplan_id = {$id} ";
  1058. $linked_items = $this->db->fetchRowsIntoMap($sql,'parent_id');
  1059. if( !is_null($linked_items) )
  1060. {
  1061. $tc_id_list = implode(",",array_keys($linked_items));
  1062. $sql = " /* $debugMsg */ " .
  1063. " SELECT DISTINCT TCKW.keyword_id,KW.keyword " .
  1064. " FROM {$this->tables['testcase_keywords']} TCKW, " .
  1065. " {$this->tables['keywords']} KW " .
  1066. " WHERE TCKW.keyword_id = KW.id " .
  1067. " AND TCKW.testcase_id IN ( {$tc_id_list} ) " .
  1068. " {$order_by_clause} ";
  1069. $map_keywords = $this->db->fetchColumnsIntoMap($sql,'keyword_id','keyword');
  1070. }
  1071. return ($map_keywords);
  1072. }
  1073. /*
  1074. args :
  1075. [$keyword_id]: can be an array
  1076. */
  1077. function get_keywords_tcases($id,$keyword_id=0)
  1078. {
  1079. $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
  1080. $CUMULATIVE=1;
  1081. $map_keywords=null;
  1082. // keywords are associated to testcase id, then first
  1083. // we need to get the list of testcases linked to the testplan
  1084. $linked_items = $this->get_linked_items_id($id);
  1085. if( !is_null($linked_items) )
  1086. {
  1087. $keyword_filter= '' ;
  1088. if( is_array($keyword_id) )
  1089. {
  1090. $keyword_filter = " AND keyword_id IN (" . implode(',',$keyword_id) . ")";
  1091. }
  1092. else if( $keyword_id > 0 )
  1093. {
  1094. $keyword_filter = " AND keyword_id = {$keyword_id} ";
  1095. }
  1096. $tc_id_list = implode(",",array_keys($linked_items));
  1097. // 20081116 - franciscom -
  1098. // Does DISTINCT is needed ? Humm now I think no.
  1099. $sql = "SELECT DISTINCT testcase_id,keyword_id,keyword
  1100. FROM {$this->tables['testcase_keywords']} testcase_keywords,
  1101. {$this->tables['keywords']} keywords
  1102. WHERE keyword_id = keywords.id
  1103. AND testcase_id IN ( {$tc_id_list} )
  1104. {$keyword_filter}
  1105. ORDER BY keyword ASC ";
  1106. // 20081116 - francis…

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