/lib/functions/testplan.class.php
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
- <?php
- /**
- * TestLink Open Source Project - http://testlink.sourceforge.net/
- * This script is distributed under the GNU General Public License 2 or later.
- *
- * Manages test plan operations and related items like Custom fields,
- * Builds, Custom fields, etc
- *
- * @package TestLink
- * @author franciscom
- * @copyright 2007-2009, TestLink community
- * @version CVS: $Id: testplan.class.php,v 1.209 2010/08/31 19:40:15 mx-julian Exp $
- * @link http://www.teamst.org/index.php
- *
- *
- * @internal Revisions:
- * 20100830 - franciscom - get_linked_tcversions() - missing cast to array $my['filters']['exec_status']
- * urgencyImportanceToPriorityLevel() - refactored
- * 20100827 - franciscom - new method wrapper - hasLinkedPlatforms()
- * 20100727 - asimon - BUGID 3629: modified statement in get_linked_tcversions()
- * 20100725 - asimon - BUGID 3497 and hopefully also 3530 fixed in unlink_tcversions()
- * 20100723 - asimon - commented out some old debug message in copy_linked_tcversions()
- * 20100722 - asimon - added missing $debugMsg to get_linked_items()
- * 20100721 - asimon - BUGID 3406: added user_assignments_per_build option to get_linked_tcversions()
- * 20100711 - franciscom - BUGID 3564 -> getPlatforms()
- * 20100614 - eloff - refactor getStatusTotalsByPriority() to same style as the other getStatusTotals...()
- * 20100610 - eloff - BUGID 3515 - getStatusTotals() now takes platforms into account
- * 20100602 - franciscom - copy_as() - force Platforms Link copy when user choose Test Case Copy
- * 20100527 - Julian - BUGID 3492 - Added execution notes to sql statement of get_linked_tcversions
- * 20100525 - Julian - changed default for steps_info option on get_linked_tcversions() to false
- * -> performance improvement because not all steps are loaded per default
- * 20100520 - franciscom - getTestCaseSiblings() join bug
- * 20100518 - franciscom - BUGID 3473
- * 20100516 - franciscom - BUGID 3465: Delete Test Project - User Execution Assignment is not deleted
- * 20100506 - franciscom - new method - get_linked_items_id(), that has perfomance advantages
- * over get_linked_tcversions() when only info needed is test case id.
- *
- * 20100505 - franciscom - BUGID 3434 - get_keywords_map() - refactoring trying to improve performance
- * 20100505 - franciscom - BUGID 3430 - copy_milestones() - need to check if start date is NOT NULL
- * 20100425 - franciscom - BUGID 2463 - changes in getStatusTotalsByAssignedTesterPlatform()
- * 20100417 - franciscom - get_linked_tcversions() added importance on output data
- * BUGID 3356: Failed Test Cases" report is not updated when a test case
- * has been changed from "Failed" to "Passed"
- *
- * 20100217 - asimon - added parameters open and active to getNumberOfBuilds()
- * 20100214 - franciscom - BUGID 2455, BUGID 3026 - Contribution by julian,asimon
- * 20100206 - eloff - BUGID 3060 - Adding getStatusTotalsByPriority()
- * 20100206 - eloff - BUGID 3060 - Adding urgencyImportanceToPriorityLevel() method
- * 20100201 - franciscom - BUGID 3121 - Adding Platform to test plan after the execution completed,
- * reports are not shown appropriate
- * 20100112 - franciscom - getPlatforms() - interface changes
- * 20100106 - franciscom - Multiple Test Case Steps Feature
- * Affected Methods: get_linked_tcversions()
- * 20091111 - franciscom - BUGID 2938 - getTestCaseSiblings(), getTestCaseNextSibling()
- * 20091031 - franciscom - tallyResultsForReport()
- * 20091027 - franciscom - BUGID 2500 - get_linked_tcversions()
- * 20091025 - franciscom - new method - getStatusTotalsByPlatform()
- * bug found on getNotExecutedLinkedTCVersionsDetailed()
- * missing testplan_id on execution join
- *
- * 20091010 - franciscom - getNotExecutedLinkedTCVersionsDetailed() new options
- * 20091004 - franciscom - get_linked_tcversions() - fixed query when requesting exec status filtering.
- * - added more columns to output record set
- * 20090923 - franciscom - link_tcversions() - will return data
- * 20090920 - franciscom - getStatusTotals(), will replace some result.class method
- * 20090919 - franciscom - copy_as(), copy_linked_tcversions() added contribution (refactored)
- * to copy user assignment.
- *
- * 20090822 - franciscom - changeLinkedTCVersionsPlatform() - new method
- * countLinkedTCVersionsByPlatform() - new method
- * 20090814 - franciscom - link_tcversions() - interface changes - due to platform feature
- * 20090516 - franciscom - BUGID - is_public
- * create(),update() changed
- * 20090509 - franciscom - BUGID - build class manage release_date
- * 20090411 - franciscom - BUGID 2369 - link_tcversions() - interface changes
- * 20090214 - franciscom - BUGID 2099 - get_linked_tcversions() - added new columns in output recordset
- * 20090208 - franciscom - testplan class - new method get_build_by_id()
- * 20090201 - franciscom - copy_milestones() - wrong SQL sentece
- * A,B,C fields renamed to lower case a,b,c to avoid problems
- * between differnt database (case and no case sensitive)
- * 20081227 - franciscom - BUGID 1913 - filter by same results on ALL previous builds
- * get_same_status_for_build_set(), get_prev_builds()
- *
- * 20081214 - franciscom - Thanks to postgres found missing CAST() on SUM()
- * 20081206 - franciscom - BUGID 1910 - get_estimated_execution_time() - added new filter
- * get_linked_tcversions() - added test suites filter
- * 20080820 - franciscom - added get_estimated_execution_time() as result of contributed idea.
- *
- * 20080811 - franciscom - BUGID 1650 (REQ)
- * 20080614 - franciscom - get_linked_and_newest_tcversions() - fixed bug (thanks to PostGres)
- * 20080428 - franciscom - supporting multiple keywords in get_linked_tcversions()
- * (based on contribution by Eugenia Drosdezki)
- * 20080310 - sbouffard - contribution added NHB.name to recordset (useful for API methods).
- * 20071010 - franciscom - BUGID MSSQL reserved word problem - open
- * 20070927 - franciscom - BUGID 1069
- * added _natsort_builds() (see natsort info on PHP manual).
- * get_builds() add call to _natsort_builds()
- * get_builds_for_html_options() add call to natsort()
- * 20070310 - franciscom - BUGID 731
- * 20070306 - franciscom - BUGID 705 - changes in get_linked_tcversions()
- **/
-
- /** related functionality */
- require_once( dirname(__FILE__) . '/tree.class.php' );
- require_once( dirname(__FILE__) . '/assignment_mgr.class.php' );
- require_once( dirname(__FILE__) . '/attachments.inc.php' );
-
- /**
- * class to coordinate and manage Test Plans
- * @package TestLink
- * @todo havlatm: create class testplanEdit (as extension of testplan class) and
- * move here create,edit,delete,copy related stuff
- * @TODO franciscom - absolutely disagree with suggested approach, see no value - 20090611
- */
- class testplan extends tlObjectWithAttachments
- {
- /** query options */
- const GET_ALL=null;
- const GET_ACTIVE_BUILD=1;
- const GET_INACTIVE_BUILD=0;
- const GET_OPEN_BUILD=1;
- const GET_CLOSED_BUILD=0;
- const ACTIVE_BUILDS=1;
- const ENABLED=1;
-
- /** @var database handler */
- var $db;
-
- var $tree_manager;
- var $assignment_mgr;
- var $cfield_mgr;
- var $tcase_mgr;
-
- var $assignment_types;
- var $assignment_status;
-
- /** message to show on GUI */
- var $user_feedback_message = '';
-
- var $node_types_descr_id;
- var $node_types_id_descr;
-
- /**
- * testplan class constructor
- *
- * @param resource &$db reference to database handler
- */
- function __construct(&$db)
- {
- $this->db = &$db;
- $this->tree_manager = New tree($this->db);
- $this->node_types_descr_id=$this->tree_manager->get_available_node_types();
- $this->node_types_id_descr=array_flip($this->node_types_descr_id);
-
- $this->assignment_mgr = new assignment_mgr($this->db);
- $this->assignment_types = $this->assignment_mgr->get_available_types();
- $this->assignment_status = $this->assignment_mgr->get_available_status();
-
- $this->cfield_mgr = new cfield_mgr($this->db);
- $this->tcase_mgr = New testcase($this->db);
- $this->platform_mgr = new tlPlatform($this->db);
-
- tlObjectWithAttachments::__construct($this->db,'testplans');
- }
-
-
- /**
- * creates a tesplan on Database, for a testproject.
- *
- * @param string $name: testplan name
- * @param string $notes: testplan notes
- * @param string $testproject_id: testplan parent
- *
- * @return integer status code
- * if everything ok -> id of new testplan (node id).
- * if problems -> 0.
- */
- function create($name,$notes,$testproject_id,$is_active=1,$is_public=1)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
-
- $node_types=$this->tree_manager->get_available_node_types();
- $tplan_id = $this->tree_manager->new_node($testproject_id,$node_types['testplan'],$name);
-
- $active_status=intval($is_active) > 0 ? 1 : 0;
- $public_status=intval($is_public) > 0 ? 1 : 0;
-
- $sql = "/* $debugMsg */ " .
- " INSERT INTO {$this->tables['testplans']} (id,notes,testproject_id,active,is_public) " .
- " VALUES ( {$tplan_id} " . ", '" . $this->db->prepare_string($notes) . "'," .
- $testproject_id . "," . $active_status . "," . $public_status . ")";
- $result = $this->db->exec_query($sql);
- $id = 0;
- if ($result)
- {
- $id = $tplan_id;
- }
-
- return $id;
- }
-
-
- /**
- * update testplan information
- *
- * @param integer $id Test plan identifier
- * @param string $name: testplan name
- * @param string $notes: testplan notes
- * @param boolean $is_active
- *
- * @return integer result code (1=ok)
- */
- function update($id,$name,$notes,$is_active=null,$is_public=null)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
- $do_update = 1;
- $result = null;
- // $active = to_boolean($is_active);
- $name = trim($name);
-
- // two tables to update and we have no transaction yet.
- $rsa = $this->get_by_id($id);
- $duplicate_check = (strcmp($rsa['name'],$name) != 0 );
-
- if($duplicate_check)
- {
- $rs = $this->get_by_name($name,$rsa['parent_id']);
- $do_update = is_null($rs);
- }
-
- if($do_update)
- {
- // Update name
- $sql = "/* $debugMsg */ ";
- $sql .= "UPDATE {$this->tables['nodes_hierarchy']} " .
- "SET name='" . $this->db->prepare_string($name) . "'" .
- "WHERE id={$id}";
- $result = $this->db->exec_query($sql);
-
- if($result)
- {
- $add_upd='';
- if( !is_null($is_active) )
- {
- $add_upd .=',active=' . (intval($is_active) > 0 ? 1 : 0);
- }
- if( !is_null($is_public) )
- {
- $add_upd .=',is_public=' . (intval($is_public) > 0 ? 1:0);
- }
-
- $sql = " UPDATE {$this->tables['testplans']} " .
- " SET notes='" . $this->db->prepare_string($notes). "' " .
- " {$add_upd} WHERE id=" . $id;
- $result = $this->db->exec_query($sql);
- }
- }
- return ($result ? 1 : 0);
- }
-
-
- /*
- function: get_by_name
- get information about a testplan using name as access key.
- Search can be narrowed, givin a testproject id as filter criteria.
-
- args: name: testplan name
- [tproject_id]: default:0 -> system wide search i.e. inside all testprojects
-
- returns: if nothing found -> null
- if found -> array where every element is a map with following keys:
- id: testplan id
- notes:
- active: active status
- is_open: open status
- name: testplan name
- testproject_id
- */
- function get_by_name($name,$tproject_id = 0)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
- $sql = "/* $debugMsg */ ";
- $sql .= " SELECT testplans.*, NH.name " .
- " FROM {$this->tables['testplans']} testplans, " .
- " {$this->tables['nodes_hierarchy']} NH" .
- " WHERE testplans.id=NH.id " .
- " AND NH.name = '" . $this->db->prepare_string($name) . "'";
-
- if($tproject_id > 0 )
- {
- $sql .= " AND NH.parent_id={$tproject_id}";
- }
-
- $recordset = $this->db->get_recordset($sql);
- return($recordset);
- }
-
-
- /*
- function: get_by_id
-
- args : id: testplan id
-
- returns: map with following keys:
- id: testplan id
- name: testplan name
- notes: testplan notes
- testproject_id
- active
- is_open
- parent_id
- */
- function get_by_id($id)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
- $sql = "/* $debugMsg */ " .
- " SELECT testplans.*,NH.name,NH.parent_id " .
- " FROM {$this->tables['testplans']} testplans, " .
- " {$this->tables['nodes_hierarchy']} NH " .
- " WHERE testplans.id = NH.id AND testplans.id = {$id}";
- $recordset = $this->db->get_recordset($sql);
- return($recordset ? $recordset[0] : null);
- }
-
-
- /*
- function: get_all
- get array of info for every test plan,
- without considering Test Project and any other kind of filter.
- Every array element contains an assoc array
-
- args : -
-
- returns: array, every element is a map with following keys:
- id: testplan id
- name: testplan name
- notes: testplan notes
- testproject_id
- active
- is_open
- parent_id
- */
- function get_all()
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
- $sql = "/* $debugMsg */ " .
- " SELECT testplans.*, NH.name " .
- " FROM {$this->tables['testplans']} testplans, " .
- " {$this->tables['nodes_hierarchy']} NH " .
- " WHERE testplans.id=NH.id";
- $recordset = $this->db->get_recordset($sql);
- return $recordset;
- }
-
- /*
- function: count_testcases
- get number of testcases linked to a testplan
-
- args: id: testplan id
-
- [platform_id]: null => do not filter by platform
-
- returns: number
- */
- public function count_testcases($id,$platform_id=null)
- {
- $sql_filter = '';
- if( !is_null($platform_id) )
- {
- $sql_filter = " AND platform_id={$platform_id} ";
- }
-
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
- $sql = "/* $debugMsg */ " .
- " SELECT COUNT(testplan_id) AS qty " .
- " FROM {$this->tables['testplan_tcversions']} " .
- " WHERE testplan_id={$id} {$sql_filter}";
- $recordset = $this->db->get_recordset($sql);
- $qty = 0;
- if(!is_null($recordset))
- {
- $qty = $recordset[0]['qty'];
- }
- return $qty;
- }
-
-
- /*
- function: tcversionInfoForAudit
- get info regarding tcversions, to generate useful audit messages
-
-
- args :
- $tplan_id: test plan id
- $items_to_link: map key=tc_id
- value: tcversion_id
- returns: -
-
- rev: 20080629 - franciscom - audit message improvements
- */
- function tcversionInfoForAudit($tplan_id,&$items)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
-
- // Get human readeable info for audit
- $ret=array();
- $tcase_cfg = config_get('testcase_cfg');
- $dummy=reset($items);
-
- list($ret['tcasePrefix'],$tproject_id) = $this->tcase_mgr->getPrefix($dummy);
- $ret['tcasePrefix'] .= $tcase_cfg->glue_character;
-
- $sql = "/* $debugMsg */ " .
- " SELECT TCV.id, tc_external_id, version, NHB.name " .
- " FROM {$this->tables['tcversions']} TCV,{$this->tables['nodes_hierarchy']} NHA, " .
- " {$this->tables['nodes_hierarchy']} NHB " .
- " WHERE NHA.id=TCV.id " .
- " AND NHB.id=NHA.parent_id " .
- " AND TCV.id IN (" . implode(',',$items) . ")";
-
- $ret['info']=$this->db->fetchRowsIntoMap($sql,'id');
- $ret['tplanInfo']=$this->get_by_id($tplan_id);
-
- return $ret;
- }
-
-
- /**
- * associates version of different test cases to a test plan.
- * this is the way to populate a test plan
-
- args :
- $id: test plan id
- $items_to_link: map key=tc_id
- value= map with
- key: platform_id (can be 0)
- value: tcversion_id
- passed by reference for speed
- returns: -
-
- rev: 20080629 - franciscom - audit message improvements
- */
- function link_tcversions($id,&$items_to_link,$userId)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
-
- // Get human readeable info for audit
- $title_separator = config_get('gui_title_separator_1');
- $auditInfo=$this->tcversionInfoForAudit($id,$items_to_link['tcversion']);
- $platformInfo = $this->platform_mgr->getLinkedToTestplanAsMap($id);
- $platformLabel = lang_get('platform');
-
- // Important: MySQL do not support default values on datetime columns that are functions
- // that's why we are using db_now().
- $sql = "/* $debugMsg */ " .
- "INSERT INTO {$this->tables['testplan_tcversions']} " .
- "(testplan_id,author_id,creation_ts,tcversion_id,platform_id) " .
- " VALUES ({$id},{$userId},{$this->db->db_now()},";
- $features=null;
- foreach($items_to_link['items'] as $tcase_id => $items)
- {
- foreach($items as $platform_id => $tcversion)
- {
- $addInfo='';
- $result = $this->db->exec_query($sql . "{$tcversion}, {$platform_id})");
- if ($result)
- {
- $features[$platform_id][$tcversion]=$this->db->insert_id($this->tables['testplan_tcversions']);
- if( isset($platformInfo[$platform_id]) )
- {
- $addInfo = ' - ' . $platformLabel . ':' . $platformInfo[$platform_id];
- }
- $auditMsg=TLS("audit_tc_added_to_testplan",
- $auditInfo['tcasePrefix'] . $auditInfo['info'][$tcversion]['tc_external_id'] .
- $title_separator . $auditInfo['info'][$tcversion]['name'],
- $auditInfo['info'][$tcversion]['version'],
- $auditInfo['tplanInfo']['name'] . $addInfo );
-
- logAuditEvent($auditMsg,"ASSIGN",$id,"testplans");
- }
- }
- }
- return $features;
- }
-
-
- /*
- function: setExecutionOrder
-
- args :
- $id: test plan id
- $executionOrder: assoc array key=tcversion_id value=order
- passed by reference for speed
-
- returns: -
- */
- function setExecutionOrder($id,&$executionOrder)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
- foreach($executionOrder as $tcVersionID => $execOrder)
- {
- $execOrder=intval($execOrder);
- $sql="/* $debugMsg */ UPDATE {$this->tables['testplan_tcversions']} " .
- "SET node_order={$execOrder} " .
- "WHERE testplan_id={$id} " .
- "AND tcversion_id={$tcVersionID}";
- $result = $this->db->exec_query($sql);
- }
- }
-
-
- /**
- *
- * @internal revisions:
- * 20100722 - asimon - added missing $debugMsg
- */
- function get_linked_items_id($id)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
- $sql = " /* $debugMsg */ ".
- " SELECT DISTINCT parent_id FROM {$this->tables['nodes_hierarchy']} NHTC " .
- " JOIN {$this->tables['testplan_tcversions']} TPTCV ON TPTCV.tcversion_id = NHTC.id " .
- " WHERE TPTCV.testplan_id = {$id} ";
-
- $linked_items = $this->db->fetchRowsIntoMap($sql,'parent_id');
- return $linked_items;
- }
-
-
- /*
- function: get_linked_tcversions
- get information about testcases linked to a testplan.
-
- args :
- id: testplan id
- [filters]: map with following keys
- [tcase_id]: default null => get any testcase
- numeric => just get info for this testcase
-
- [keyword_id]: default 0 => do not filter by keyword id
- numeric => filter by keyword id
-
-
- [assigned_to]: default NULL => do not filter by user assign.
- array() with user id to be used on filter
-
- [exec_status]: default NULL => do not filter by execution status
- character or array => filter by execution status=character
-
- [build_id]: default 0 => do not filter by build id
- numeric => filter by build id
-
- [cf_hash]: default null => do not filter by Custom Fields values
-
-
- [urgencyImportance] : filter only Tc's with certain (urgency*importance)-value
-
- [tsuites_id]: default null.
- If present only tcversions that are children of this testsuites
- will be included
- [exec_type] default null -> all types.
- [platform_id]
-
- [options]: map with following keys
- [output]: controls data type returned
- default: map -> map indexed by test case id (original return type)
- Using this option is (in a certain way) as having
- added DISTINCT on SQL clause.
- YOU WILL GET ONLY LAST EXECUTION (means one record)
- of each test case.
-
- mapOfMap: first key testcase_id, second key platform_id
- You GET ONLY LAST EXECUTION (means one record)
- of each test case.
-
- mapOfArray -> indexed by test case id but with an array
- where each element contains information
- according to Platform.
- Be carefull if you have multiple executions
- for same (testcase,platform) YOU WILL GET
- MULTIPLE ELEMENTS IN ARRAY
-
- array -> indexed sequentially.
-
-
-
- [only_executed]: default false => get executed and NOT executed
- get only executed tcversions
-
- [execution_details]: default NULL => by platftorm
- add_build => by build AND platform
-
- [last_execution]: default false => return all executions
- true => last execution ( MAX(E.id))
-
- [include_unassigned]: has effects only if [assigned_to] <> null.
- default: false
- true: also testcase not assigned will be retreived
-
- [details]: controls columns returned
- default 'simple'
- 'full': add summary, steps and expected_results, and test suite name
- 'summary': add summary
- [steps_info]: controls if step info has to be added on output
- default true
- [user_assignments_per_build]: contains a build ID, for which the
- assigned user shall get loaded
-
-
- returns: changes according options['output'] (see above)
-
- Notice:
- executed field: will take the following values
- - NULL if the tc version has not been executed in THIS test plan.
- - tcversion_id if has executions.
-
- rev :
- 20100727 - asimon - BUGID 3629: modified statement
- 20100721 - asimon - BUGID 3406: added user_assignments_per_build option
- 20100520 - franciscom - added option steps_info, to try to solve perfomance problems
- allowing caller to ask for NO INFO ABOUT STEPS
- 20100417 - franciscom - added importance on output data
- BUGID 3356: "Failed Test Cases" report is not updated when a test case
- has been changed from "Failed" to "Passed"
-
- 20090814 - franciscom - interface changes due to platform feature
- */
- public function get_linked_tcversions($id,$filters=null,$options=null)
- {
- $debugMsg = 'Class: ' . __CLASS__ . ' - Method:' . __FUNCTION__;
-
- $my = array ('filters' => '', 'options' => '');
- $tcversion_exec_type = array('join' => '', 'filter' => '');
- $tc_id = array('join' => '', 'filter' => '');
- $builds = array('join' => '', 'filter' => '');
- $keywords = array('join' => '', 'filter' => '');
- $executions = array('join' => '', 'filter' => '');
- $platforms = array('join' => '', 'filter' => '');
-
- $my['filters'] = array('tcase_id' => null, 'keyword_id' => 0,
- 'assigned_to' => null, 'exec_status' => null,
- 'build_id' => 0, 'cf_hash' => null,
- 'urgencyImportance' => null, 'tsuites_id' => null,
- 'platform_id' => null, 'exec_type' => null);
-
- $my['options'] = array('only_executed' => false, 'include_unassigned' => false,
- 'output' => 'map', 'details' => 'simple', 'steps_info' => false,
- 'execution_details' => null, 'last_execution' => false);
-
- // Cast to array to handle $options = null
- $my['filters'] = array_merge($my['filters'], (array)$filters);
- $my['options'] = array_merge($my['options'], (array)$options);
-
- // 20100830 - franciscom - bug found by Julian
- $my['filters']['exec_status'] = (array)$my['filters']['exec_status'];
-
- // new dBug($my['filters']);
- // new dBug($my['options']);
-
- $groupByPlatform=($my['options']['output']=='mapOfMap' ||
- $my['options']['output']=='mapOfMapExecPlatform') ? ',platform_id' : '';
- $groupByBuild=($my['options']['execution_details'] == 'add_build') ? ',build_id' : '';
-
- // BUGID 3406: user assignments per build
- $ua_build = isset($my['options']['user_assignments_per_build']) ?
- $my['options']['user_assignments_per_build'] : 0;
-
- // BUGID 3629
- $ua_build_sql = $ua_build && is_numeric($ua_build) ? " AND UA.build_id={$ua_build} " : " ";
-
- // @TODO - 20091004 - franciscom
- // Think that this subquery in not good when we add execution filter
- // $last_exec_subquery = " AND E.id IN ( SELECT MAX(id) " .
- // " FROM {$this->tables['executions']} executions " .
- // " WHERE testplan_id={$id} %EXECSTATUSFILTER%" .
- // " GROUP BY tcversion_id,testplan_id {$groupByPlatform} {$groupByBuild} )";
-
- // I've had confirmation of BAD query;
- // BUGID 3356: "Failed Test Cases" report is not updated when a test case
- // has been changed from "Failed" to "Passed"
- //
- // SUBQUERY CAN NOT HAVE ANY KIND OF FILTERING other that test plan.
- // Adding exec status, means that we will get last exec WITH THIS STATUS, and not THE LATEST EXEC
- $last_exec_subquery = " AND E.id IN ( SELECT MAX(id) " .
- " FROM {$this->tables['executions']} executions " .
- " WHERE testplan_id={$id} " .
- " GROUP BY tcversion_id,testplan_id {$groupByPlatform} {$groupByBuild} )";
-
-
-
- $resultsCfg = config_get('results');
- $status_not_run=$resultsCfg['status_code']['not_run'];
- $sql_subquery='';
-
- // franciscom
- // WARNING:
- // Order of analisys seems to be critic, because $executions['filter'] is overwritten
- // on some situation below if filtering on execution status is requested
- if( $my['options']['last_execution'] )
- {
- $executions['filter'] = " {$last_exec_subquery} ";
- // 20100417 - franciscom - BUGID 3356
- // $executions['filter'] = str_ireplace("%EXECSTATUSFILTER%", "", $executions['filter']);
- }
-
- if( !is_null($my['filters']['platform_id']) )
- {
- $platforms['filter'] = " AND T.platform_id = {$my['filters']['platform_id']} ";
- }
-
- // 20100417- Why to use a list ? - must be checked if is on
- if( !is_null($my['filters']['exec_type']) )
- {
- $tcversion_exec_type['filter'] = "AND TCV.execution_type IN (" .
- implode(",",(array)$my['filters']['exec_type']) . " ) ";
- }
-
- // Based on work by Eugenia Drosdezki
- if( is_array($my['filters']['keyword_id']) )
- {
- // 0 -> no keyword, remove
- if( $my['filters']['keyword_id'][0] == 0 )
- {
- array_shift($my['filters']['keyword_id']);
- }
-
- if(count($my['filters']['keyword_id']))
- {
- $keywords['filter'] = " AND TK.keyword_id IN (" . implode(',',$my['filters']['keyword_id']) . ")";
- }
- }
- else if($my['filters']['keyword_id'] > 0)
- {
- $keywords['filter'] = " AND TK.keyword_id = {$my['filters']['keyword_id']} ";
- }
-
- if(trim($keywords['filter']) != "")
- {
- $keywords['join'] = " JOIN {$this->tables['testcase_keywords']} TK ON NHA.parent_id = TK.testcase_id ";
- }
-
- if (!is_null($my['filters']['tcase_id']) )
- {
- if( is_array($my['filters']['tcase_id']) )
- {
- $tc_id['filter'] = " AND NHA.parent_id IN (" . implode(',',$my['filters']['tcase_id']) . ")";
- }
- else if ($my['filters']['tcase_id'] > 0 )
- {
- $tc_id['filter'] = " AND NHA.parent_id = {$my['filters']['tcase_id']} ";
- }
- }
-
- // --------------------------------------------------------------
- if(!is_null($my['filters']['exec_status']) )
- {
- $executions['filter'] = '';
- $notrun['filter'] = null;
- $otherexec['filter'] = null;
-
- $notRunPresent = array_search($status_not_run,$my['filters']['exec_status']);
- if($notRunPresent !== false)
- {
- $notrun['filter'] = " E.status IS NULL ";
- unset($my['filters']['exec_status'][$notRunPresent]);
- }
-
- if(count($my['filters']['exec_status']) > 0)
- {
- $otherexec['filter']=" E.status IN ('" . implode("','",$my['filters']['exec_status']) . "') ";
-
- // 20100417 - franciscom - BUGID 3356
- // $status_filter=str_ireplace("E.", "executions.", $otherexec['filter']);
- // $sql_subquery = str_ireplace("%EXECSTATUSFILTER%", "AND {$status_filter}", $last_exec_subquery);
-
- // code commented before BUGID 3356
- // $sql_subquery = str_ireplace("E.", "executions.", $sql_subquery);
- // $sql_subquery = $last_exec_subquery;
-
- // 20100417 - franciscom - BUGID 3356
- // $executions['filter'] = " ( {$otherexec['filter']} {$sql_subquery} ) ";
- $executions['filter'] = " ( {$otherexec['filter']} {$last_exec_subquery} ) ";
- }
- if( !is_null($notrun['filter']) )
- {
- if($executions['filter'] != "")
- {
- $executions['filter'] .= " OR ";
- }
- $executions['filter'] .= $notrun['filter'];
- }
-
- if($executions['filter'] != "")
- {
- // Just add the AND
- $executions['filter'] = " AND ({$executions['filter']} )";
- }
- }
-
- // --------------------------------------------------------------
- if( $my['filters']['build_id'] > 0 )
- {
- $builds['filter'] = " AND E.build_id={$my['filters']['build_id']} ";
- }
-
- // there are several situation where you need to use LEFT OUTER
- if(!$my['options']['only_executed'])
- {
- $executions['join'] = " LEFT OUTER ";
- }
-
-
- // platform feature
- $executions['join'] .= " JOIN {$this->tables['executions']} E ON " .
- " (NHA.id = E.tcversion_id AND " .
- " E.platform_id=T.platform_id AND " .
- " E.testplan_id=T.testplan_id {$builds['filter']}) ";
- // --------------------------------------------------------------
-
- $more_tcase_fields = '';
- $join_for_parent = '';
- $more_parent_fields = '';
- $more_exec_fields='';
- switch($my['options']['details'])
- {
- case 'full':
- $more_tcase_fields .= 'TCV.summary,';
- $join_for_parent .= " JOIN {$this->tables['nodes_hierarchy']} NHC ON NHB.parent_id = NHC.id ";
- $more_parent_fields .= 'NHC.name as tsuite_name,';
- break;
-
- case 'summary':
- $more_tcase_fields .= 'TCV.summary,';
- break;
-
- }
- if($my['options']['execution_details'] == 'add_build')
- {
- $more_exec_fields .= 'E.build_id,B.name AS build_name,';
- $builds['join']=" LEFT OUTER JOIN {$this->tables['builds']} B ON B.id=E.build_id ";
- }
-
- // BUGID 3406 - assignments per build
- // BUGID 3492 - Added execution notes to sql statement of get_linked_tcversions
- $sql = "/* $debugMsg */ " .
- " SELECT NHB.parent_id AS testsuite_id, {$more_tcase_fields} {$more_parent_fields}" .
- " NHA.parent_id AS tc_id, NHB.node_order AS z, NHB.name," .
- " T.platform_id, PLAT.name as platform_name ,T.id AS feature_id, T.tcversion_id AS tcversion_id, " .
- " T.node_order AS execution_order, T.creation_ts AS linked_ts, T.author_id AS linked_by," .
- " TCV.version AS version, TCV.active," .
- " TCV.tc_external_id AS external_id, TCV.execution_type,TCV.importance," .
- " E.id AS exec_id, E.tcversion_number," .
- " E.tcversion_id AS executed, E.testplan_id AS exec_on_tplan, {$more_exec_fields}" .
- " E.execution_type AS execution_run_type, E.testplan_id AS exec_on_tplan, " .
- " E.execution_ts, E.tester_id, E.notes as execution_notes, ".
- " UA.build_id as assigned_build_id, " . // 3406
- " UA.user_id,UA.type,UA.status,UA.assigner_id,T.urgency, " .
- " COALESCE(E.status,'" . $status_not_run . "') AS exec_status, ".
- " (urgency * importance) AS priority " .
- " FROM {$this->tables['nodes_hierarchy']} NHA " .
- " JOIN {$this->tables['nodes_hierarchy']} NHB ON NHA.parent_id = NHB.id " .
- $join_for_parent .
- " JOIN {$this->tables['testplan_tcversions']} T ON NHA.id = T.tcversion_id " .
- " JOIN {$this->tables['tcversions']} TCV ON NHA.id = TCV.id {$tcversion_exec_type['filter']} " .
- " {$executions['join']} " .
- " {$keywords['join']} " .
- " {$builds['join']} " .
- " LEFT OUTER JOIN {$this->tables['platforms']} PLAT ON PLAT.id = T.platform_id " .
- " LEFT OUTER JOIN {$this->tables['user_assignments']} UA ON UA.feature_id = T.id " .
- " {$ua_build_sql} " . // 3406
- " WHERE T.testplan_id={$id} {$keywords['filter']} {$tc_id['filter']} {$platforms['filter']}" .
- " AND (UA.type={$this->assignment_types['testcase_execution']['id']} OR UA.type IS NULL) " .
- $executions['filter'];
-
- // 20081220 - franciscom
- // if (!is_null($assigned_to) && $assigned_to > 0)
- // {
- //
- // If special user id TL_USER_ANYBODY is present in set of user id,
- // we will DO NOT FILTER by user ID
- if( !is_null($my['filters']['assigned_to']) &&
- !in_array(TL_USER_ANYBODY,(array)$my['filters']['assigned_to']) )
- {
- $sql .= " AND ";
-
- // Warning!!!:
- // If special user id TL_USER_NOBODY is present in set of user id
- // we will ignore any other user id present on set.
- if( in_array(TL_USER_NOBODY,(array)$my['filters']['assigned_to']) )
- {
- $sql .= " UA.user_id IS NULL ";
- }
- // BUGID 2455
- // new user filter "somebody" --> all asigned testcases
- else if( in_array(TL_USER_SOMEBODY,(array)$my['filters']['assigned_to']) )
- {
- $sql .= " UA.user_id IS NOT NULL ";
- }
- else
- {
- $sql_unassigned="";
- if( $my['options']['include_unassigned'] )
- {
- $sql .= "(";
- $sql_unassigned=" OR UA.user_id IS NULL)";
- }
- // BUGID 2500
- $sql .= " UA.user_id IN (" . implode(",",(array)$my['filters']['assigned_to']) . ") " . $sql_unassigned;
- }
- }
-
- if (!is_null($my['filters']['urgencyImportance']))
- {
- $urgencyImportanceCfg = config_get("urgencyImportance");
- if ($my['filters']['urgencyImportance'] == HIGH)
- {
- $sql .= " AND (urgency * importance) >= " . $urgencyImportanceCfg->threshold['high'];
- }
- else if($my['filters']['urgencyImportance'] == LOW)
- {
- $sql .= " AND (urgency * importance) < " . $urgencyImportanceCfg->threshold['low'];
- }
- else
- {
- $sql .= " AND ( ((urgency * importance) >= " . $urgencyImportanceCfg->threshold['low'] .
- " AND ((urgency * importance) < " . $urgencyImportanceCfg->threshold['high']."))) ";
- }
- }
-
- // test suites filter
- if (!is_null($my['filters']['tsuites_id']))
- {
- $tsuiteSet = is_array($my['filters']['tsuites_id']) ? $my['filters']['tsuites_id'] : array($my['filters']['tsuites_id']);
- $sql .= " AND NHB.parent_id IN (" . implode(',',$tsuiteSet) . ")";
- }
- $sql .= " ORDER BY testsuite_id,NHB.node_order,tc_id,platform_id,E.id ASC";
-
- switch($my['options']['output'])
- {
- case 'array':
- $recordset = $this->db->get_recordset($sql);
- break;
-
- case 'mapOfArray':
- $recordset = $this->db->fetchRowsIntoMap($sql,'tc_id',database::CUMULATIVE);
- break;
-
- case 'mapOfMap':
- // with this option we got just one record for each (testcase,platform)
- // no matter how many executions has been done
-
- $recordset = $this->db->fetchMapRowsIntoMap($sql,'tc_id','platform_id');
- break;
-
- case 'mapOfMapExecPlatform':
- // with this option we got just one record for each (platform, build)
-
- $recordset = $this->db->fetchMapRowsIntoMap($sql,'exec_id','platform_id');
- break;
-
- case 'map':
- default:
- $recordset = $this->db->fetchRowsIntoMap($sql,'tc_id');
-
- // 20070913 - jbarchibald
- // here we add functionality to filter out the custom field selections
- //
- // After addition of platform feature, this filtering can not be done
- // always with original filter_cf_selection().
- // Fisrt choice:
- // Enable this feature only if recordset maintains original structured
- //
- if (!is_null($my['filters']['cf_hash'])) {
- $recordset = $this->filter_cf_selection($recordset, $my['filters']['cf_hash']);
- }
- break;
- }
-
- // Multiple Test Case Steps Feature
- // added after Julian mail regarding perf problems building exec tree
- if( !is_null($recordset) && $my['options']['steps_info'])
- {
- $itemSet = array_keys($recordset);
- switch($my['options']['output'])
- {
-
- case 'mapOfArray':
- case 'mapOfMap':
- foreach($itemSet as $itemKey)
- {
- $keySet = array_keys($recordset[$itemKey]);
- $target = &$recordset[$itemKey];
- foreach($keySet as $accessKey)
- {
- $step_set = $this->tcase_mgr->get_steps($target[$accessKey]['tcversion_id']);
- $target[$accessKey]['steps'] = $step_set;
- }
- }
- break;
-
- case 'array':
- case 'map':
- default:
- foreach($itemSet as $accessKey)
- {
- $step_set = $this->tcase_mgr->get_steps($recordset[$accessKey]['tcversion_id']);
- $recordset[$accessKey]['steps'] = $step_set;
- }
- break;
- }
- }
-
-
- return $recordset;
- }
-
-
- /*
- function: get_linked_and_newest_tcversions
- returns for every test case in a test plan
- the tc version linked and the newest available version
-
- args: id: testplan id
- [tcase_id]: default null => all testcases linked to testplan
-
- returns: map key: testcase internal id
- values: map with following keys:
-
- [name]
- [tc_id] (internal id)
- [tcversion_id]
- [newest_tcversion_id]
- [tc_external_id]
- [version] (for humans)
- [newest_version] (for humans)
-
- rev:
- 20080614 - franciscom - fixed bug on SQL generated while
- adding tc_external_id on results.
- 20080126 - franciscom - added tc_external_id on results
- */
- function get_linked_and_newest_tcversions($id,$tcase_id=null)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
-
- $tc_id_filter = " ";
- if (!is_null($tcase_id) )
- {
- if( is_array($tcase_id) )
- {
- // ??? implement as in ?
- }
- else if ($tcase_id > 0 )
- {
- $tc_id_filter = " AND NHA.parent_id = {$tcase_id} ";
- }
- }
-
- // 20080614 - franciscom
- // Peter Rooms found bug due to wrong SQL, accepted by MySQL but not by PostGres
- // Missing column in GROUP BY Clause
-
- $sql = " SELECT MAX(NHB.id) AS newest_tcversion_id, " .
- " NHA.parent_id AS tc_id, NHC.name, T.tcversion_id AS tcversion_id," .
- " TCVA.tc_external_id AS tc_external_id, TCVA.version AS version " .
- " FROM {$this->tables['nodes_hierarchy']} NHA " .
-
- // NHA - will contain ONLY nodes of type testcase_version that are LINKED to test plan
- " JOIN {$this->tables['testplan_tcversions']} T ON NHA.id = T.tcversion_id " .
-
- // Get testcase_version data for LINKED VERSIONS
- " JOIN {$this->tables['tcversions']} TCVA ON TCVA.id = T.tcversion_id" .
-
- // Work on Sibblings - Start
- // NHB - Needed to get ALL testcase_version sibblings nodes
- " JOIN {$this->tables['nodes_hierarchy']} NHB ON NHB.parent_id = NHA.parent_id " .
-
- // Want only ACTIVE Sibblings
- " JOIN {$this->tables['tcversions']} TCVB ON TCVB.id = NHB.id AND TCVB.active=1 " .
- // Work on Sibblings - STOP
-
- // NHC will contain - nodes of type TESTCASE (parent of testcase versions we are working on)
- // we use NHC to get testcase NAME ( testcase version nodes have EMPTY NAME)
- " JOIN {$this->tables['nodes_hierarchy']} NHC ON NHC.id = NHA.parent_id " .
-
- // Want to get only testcase version with id (NHB.id) greater than linked one (NHA.id)
- " WHERE T.testplan_id={$id} AND NHB.id > NHA.id" . $tc_id_filter .
- " GROUP BY NHA.parent_id, NHC.name, T.tcversion_id, TCVA.tc_external_id, TCVA.version ";
-
- $sql2 = " SELECT SUBQ.name, SUBQ.newest_tcversion_id, SUBQ.tc_id, " .
- " SUBQ.tcversion_id, SUBQ.version, SUBQ.tc_external_id, " .
- " TCV.version AS newest_version " .
- " FROM {$this->tables['tcversions']} TCV, ( $sql ) AS SUBQ " .
- " WHERE SUBQ.newest_tcversion_id = TCV.id " .
- " ORDER BY SUBQ.tc_id ";
-
- return $this->db->fetchRowsIntoMap($sql2,'tc_id');
- }
-
-
- /**
- * Remove of records from user_assignments table
- * @author franciscom
- *
- * @param integer $id : test plan id
- * @param array $items: assoc array key=tc_id value=tcversion_id
- *
- * @internal revisions:
- * 20100725 - asimon - BUGID 3497 and hopefully also 3530
- */
- function unlink_tcversions($id,&$items)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
- if(is_null($items))
- {
- return;
- }
-
- // Get human readeable info for audit
- $gui_cfg = config_get('gui');
- $title_separator = config_get('gui_title_separator_1');
- $auditInfo=$this->tcversionInfoForAudit($id,$items['tcversion']);
- $platformInfo = $this->platform_mgr->getLinkedToTestplanAsMap($id);
- $platformLabel = lang_get('platform');
-
- $dummy = null;
- foreach($items['items'] as $tcase_id => $elem)
- {
- foreach($elem as $platform_id => $tcversion_id)
- {
- $dummy[] = "(tcversion_id = {$tcversion_id} AND platform_id = {$platform_id})";
- }
- }
- $where_clause = implode(" OR ", $dummy);
-
- /*
- * asimon - BUGID 3497 and hopefully also 3530
- * A very litte error, missing braces in the $where_clause, was causing this bug.
- * When one set of testcases is linked to two testplans, this statement should check
- * that the combination of testplan_id, tcversion_id and platform_id was the same,
- * but instead it checked for either testplan_id OR tcversion_id and platform_id.
- * So every linked testcase with fitting tcversion_id and platform_id without execution
- * was deleted, regardless of testplan_id.
- * Simply adding braces around the where clause solves this.
- * So innstead of:
- * SELECT id AS link_id FROM testplan_tcversions
- * WHERE testplan_id=12 AND (tcversion_id = 5 AND platform_id = 0)
- * OR (tcversion_id = 7 AND platform_id = 0)
- * OR (tcversion_id = 9 AND platform_id = 0)
- * OR (tcversion_id = 11 AND platform_id = 0)
- * we need this:
- * SELECT ... WHERE testplan_id=12 AND (... OR ...)
- */
- $where_clause = " ( {$where_clause} ) ";
-
- // First get the executions id if any exist
- $sql=" SELECT id AS execution_id " .
- " FROM {$this->tables['executions']} " .
- " WHERE testplan_id = {$id} AND ${where_clause}";
- $exec_ids = $this->db->fetchRowsIntoMap($sql,'execution_id');
-
- if( !is_null($exec_ids) and count($exec_ids) > 0 )
- {
- // has executions
- $exec_ids = array_keys($exec_ids);
- $exec_id_where= " WHERE execution_id IN (" . implode(",",$exec_ids) . ")";
-
- // Remove bugs if any exist
- $sql=" DELETE FROM {$this->tables['execution_bugs']} {$exec_id_where} ";
- $result = $this->db->exec_query($sql);
-
- // now remove executions
- $sql=" DELETE FROM {$this->tables['executions']} " .
- " WHERE testplan_id = {$id} AND ${where_clause}";
- $result = $this->db->exec_query($sql);
- }
-
- // ----------------------------------------------------------------
- // to remove the assignment to users (if any exists) we need the list of id
- $sql=" SELECT id AS link_id FROM {$this->tables['testplan_tcversions']} " .
- " WHERE testplan_id={$id} AND {$where_clause} ";
- $link_ids = $this->db->fetchRowsIntoMap($sql,'link_id');
- $features = array_keys($link_ids);
- if( count($features) == 1)
- {
- $features=$features[0];
- }
- $this->assignment_mgr->delete_by_feature_id($features);
- // ----------------------------------------------------------------
-
- // Delete from link table
- $sql=" DELETE FROM {$this->tables['testplan_tcversions']} " .
- " WHERE testplan_id={$id} AND {$where_clause} ";
- $result = $this->db->exec_query($sql);
-
- foreach($items['items'] as $tcase_id => $elem)
- {
- foreach($elem as $platform_id => $tcversion)
- {
- $addInfo='';
- if( isset($platformInfo[$platform_id]) )
- {
- $addInfo = ' - ' . $platformLabel . ':' . $platformInfo[$platform_id];
- }
- $auditMsg=TLS("audit_tc_removed_from_testplan",
- $auditInfo['tcasePrefix'] . $auditInfo['info'][$tcversion]['tc_external_id'] .
- $title_separator . $auditInfo['info'][$tcversion]['name'],
- $auditInfo['info'][$tcversion]['version'],
- $auditInfo['tplanInfo']['name'] . $addInfo );
-
- logAuditEvent($auditMsg,"UNASSIGN",$id,"testplans");
- }
- }
-
- } // end function unlink_tcversions
-
-
-
- /**
- *
- * @internal revisions
- * 20100505 - franciscom - BUGID 3434
- */
- function get_keywords_map($id,$order_by_clause='')
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
- $map_keywords=null;
-
- // keywords are associated to testcase id, then first
- // we need to get the list of testcases linked to the testplan
- //
- // 20100505 - according to user report (BUGID 3434) seems that
- // $linked_items = $this->get_linked_tcversions($id);
- // has performance problems.
- // Then make a choice do simple query here.
- //
- $sql = " /* $debugMsg */ ".
- " SELECT DISTINCT parent_id FROM {$this->tables['nodes_hierarchy']} NHTC " .
- " JOIN {$this->tables['testplan_tcversions']} TPTCV ON TPTCV.tcversion_id = NHTC.id " .
- " WHERE TPTCV.testplan_id = {$id} ";
-
- $linked_items = $this->db->fetchRowsIntoMap($sql,'parent_id');
-
- if( !is_null($linked_items) )
- {
- $tc_id_list = implode(",",array_keys($linked_items));
-
- $sql = " /* $debugMsg */ " .
- " SELECT DISTINCT TCKW.keyword_id,KW.keyword " .
- " FROM {$this->tables['testcase_keywords']} TCKW, " .
- " {$this->tables['keywords']} KW " .
- " WHERE TCKW.keyword_id = KW.id " .
- " AND TCKW.testcase_id IN ( {$tc_id_list} ) " .
- " {$order_by_clause} ";
- $map_keywords = $this->db->fetchColumnsIntoMap($sql,'keyword_id','keyword');
- }
- return ($map_keywords);
- }
-
-
- /*
- args :
- [$keyword_id]: can be an array
- */
- function get_keywords_tcases($id,$keyword_id=0)
- {
- $debugMsg = 'Class:' . __CLASS__ . ' - Method: ' . __FUNCTION__;
-
- $CUMULATIVE=1;
- $map_keywords=null;
-
- // keywords are associated to testcase id, then first
- // we need to get the list of testcases linked to the testplan
- $linked_items = $this->get_linked_items_id($id);
- if( !is_null($linked_items) )
- {
- $keyword_filter= '' ;
-
- if( is_array($keyword_id) )
- {
- $keyword_filter = " AND keyword_id IN (" . implode(',',$keyword_id) . ")";
- }
- else if( $keyword_id > 0 )
- {
- $keyword_filter = " AND keyword_id = {$keyword_id} ";
- }
-
-
- $tc_id_list = implode(",",array_keys($linked_items));
-
- // 20081116 - franciscom -
- // Does DISTINCT is needed ? Humm now I think no.
- $sql = "SELECT DISTINCT testcase_id,keyword_id,keyword
- FROM {$this->tables['testcase_keywords']} testcase_keywords,
- {$this->tables['keywords']} keywords
- WHERE keyword_id = keywords.id
- AND testcase_id IN ( {$tc_id_list} )
- {$keyword_filter}
- ORDER BY keyword ASC ";
-
- // 20081116 - francis…
Large files files are truncated, but you can click here to view the full file