function testPlanTree(&$dbHandler, &$menuUrl, $tproject_id, $tproject_name, $tplan_id, $tplan_name, $objFilters, $objOptions) { $debugMsg = ' - Method: ' . __FUNCTION__; $chronos[] = $tstart = microtime(true); $treeMenu = new stdClass(); $treeMenu->rootnode = null; $treeMenu->menustring = ''; $resultsCfg = config_get('results'); $glueChar = config_get('testcase_cfg')->glue_character; $menustring = null; $tplan_tcases = null; $renderTreeNodeOpt = null; $renderTreeNodeOpt['showTestCaseID'] = config_get('treemenu_show_testcase_id'); list($filters, $options, $renderTreeNodeOpt['showTestSuiteContents'], $renderTreeNodeOpt['useCounters'], $renderTreeNodeOpt['useColors'], $colorBySelectedBuild) = initExecTree($objFilters, $objOptions); $tplan_mgr = new testplan($dbHandler); $tproject_mgr = new testproject($dbHandler); $tree_manager = $tplan_mgr->tree_manager; $tcase_node_type = $tree_manager->node_descr_id['testcase']; $hash_descr_id = $tree_manager->get_available_node_types(); $hash_id_descr = array_flip($hash_descr_id); $tcase_prefix = $tproject_mgr->getTestCasePrefix($tproject_id) . $glueChar; $nt2exclude = array('testplan' => 'exclude_me', 'requirement_spec' => 'exclude_me', 'requirement' => 'exclude_me'); $nt2exclude_children = array('testcase' => 'exclude_my_children', 'requirement_spec' => 'exclude_my_children'); // remove test spec, test suites (or branches) that have ZERO test cases linked to test plan // // IMPORTANT: // using 'order_cfg' => array("type" =>'exec_order',"tplan_id" => $tplan_id)) // makes the magic of ignoring test cases not linked to test plan. // This unexpected bonus can be useful on export test plan as XML. // $my['options'] = array('recursive' => true, 'remove_empty_nodes_of_type' => $tree_manager->node_descr_id['testsuite'], 'order_cfg' => array("type" => 'exec_order', "tplan_id" => $tplan_id), 'hideTestCases' => $options['hideTestCases'], 'tc_action_enabled' => $options['tc_action_enabled'], 'showTestCaseExecStatus' => $options['showTestCaseExecStatus']); $my['filters'] = array('exclude_node_types' => $nt2exclude, 'exclude_children_of' => $nt2exclude_children); if (isset($objFilters->filter_toplevel_testsuite) && is_array($objFilters->filter_toplevel_testsuite)) { $my['filters']['exclude_branches'] = $objFilters->filter_toplevel_testsuite; } if (isset($objFilters->filter_custom_fields) && is_array($objFilters->filter_custom_fields)) { $my['filters']['filter_custom_fields'] = $objFilters->filter_custom_fields; } if (property_exists($objOptions, 'actionJS')) { foreach (array('testproject', 'testsuite', 'testcase') as $nk) { if (isset($objOptions->actionJS[$nk])) { $renderTreeNodeOpt['actionJS'][$nk] = $objOptions->actionJS[$nk]; } } } if (property_exists($objOptions, 'nodeHelpText')) { foreach (array('testproject', 'testsuite', 'testcase') as $nk) { if (isset($objOptions->nodeHelpText[$nk])) { $renderTreeNodeOpt['nodeHelpText'][$nk] = $objOptions->nodeHelpText[$nk]; } } } $test_spec = $tplan_mgr->getSkeleton($tplan_id, $tproject_id, $my['filters'], $my['options']); $test_spec['name'] = $tproject_name . " / " . $tplan_name; // To be discussed $test_spec['id'] = $tproject_id; $test_spec['node_type_id'] = $hash_descr_id['testproject']; $test_spec['node_type'] = 'testproject'; $map_node_tccount = array(); $tplan_tcases = array(); if ($test_spec) { if (is_null($filters['tcase_id']) || $filters['tcase_id'] > 0) { // Step 1 - get item set with exec status. // This has to scopes: // 1. tree coloring according exec status on (Test plan, platform, build ) context // 2. produce sql that can be used to reduce item set on combination with filters // that can not be used on this step like: // a. test cases belonging to branch with root TEST SUITE // b. keyword filter on AND MODE // c. execution results on other builds, any build etc // // WE NEED TO ADD FILTERING on CUSTOM FIELD VALUES, WE HAVE NOT REFACTORED // THIS YET. // if (!is_null($sql2do = $tplan_mgr->{$objOptions->getTreeMethod}($tplan_id, $filters, $options))) { $doPinBall = false; if (is_array($sql2do)) { if ($doPinBall = $filters['keyword_filter_type'] == 'And') { $kmethod = "fetchRowsIntoMapAddRC"; $unionClause = " UNION ALL "; } else { $kmethod = "fetchRowsIntoMap"; $unionClause = ' UNION '; } $sql2run = $sql2do['exec'] . $unionClause . $sql2do['not_run']; } else { $kmethod = "fetchRowsIntoMap"; $sql2run = $sql2do; } $tplan_tcases = $dbHandler->{$kmethod}($sql2run, 'tcase_id'); if ($doPinBall && !is_null($tplan_tcases)) { $kwc = count($filters['keyword_id']); $ak = array_keys($tplan_tcases); $mx = null; foreach ($ak as $tk) { if ($tplan_tcases[$tk]['recordcount'] == $kwc) { $mx[$tk] = $tplan_tcases[$tk]; } } $tplan_tcases = null; $tplan_tcases = $mx; } $setTestCaseStatus = $tplan_tcases; } } if (is_null($tplan_tcases)) { $tplan_tcases = array(); } // OK, now we need to work on status filters // if "any" was selected as filtering status, don't filter by status $targetExecStatus = (array) (isset($objFilters->filter_result_result) ? $objFilters->filter_result_result : null); if (!is_null($targetExecStatus) && !in_array($resultsCfg['status_code']['all'], $targetExecStatus)) { applyStatusFilters($tplan_id, $tplan_tcases, $objFilters, $tplan_mgr, $resultsCfg['status_code']); } if (isset($my['filters']['filter_custom_fields']) && isset($test_spec['childNodes'])) { $test_spec['childNodes'] = filter_by_cf_values($dbHandler, $test_spec['childNodes'], $my['filters']['filter_custom_fields'], $hash_descr_id); } // here we have LOT OF CONFUSION, sometimes we use $my['options'] other $options $pnFilters = null; $pnOptions = array('hideTestCases' => $my['options']['hideTestCases'], 'viewType' => 'executionTree'); $testcase_counters = prepareExecTreeNode($dbHandler, $test_spec, $map_node_tccount, $tplan_tcases, $pnFilters, $pnOptions); foreach ($testcase_counters as $key => $value) { $test_spec[$key] = $testcase_counters[$key]; } $keys = array_keys($tplan_tcases); $renderTreeNodeOpt['hideTestCases'] = $my['options']['hideTestCases']; // $renderTreeNodeOpt['tc_action_enabled'] = 1; $renderTreeNodeOpt['tc_action_enabled'] = isset($my['options']['tc_action_enabled']) ? $my['options']['tc_action_enabled'] : 1; // $renderTreeNodeOpt['nodeHelpText'] = $my['options']['nodeHelpText']; $renderTreeNodeOpt['showTestCaseExecStatus'] = $my['options']['showTestCaseExecStatus']; $menustring = renderExecTreeNode(1, $test_spec, $tplan_tcases, $hash_id_descr, $menuUrl, $tcase_prefix, $renderTreeNodeOpt); } // if($test_spec) $treeMenu->rootnode = new stdClass(); $treeMenu->rootnode->name = $test_spec['text']; $treeMenu->rootnode->id = $test_spec['id']; $treeMenu->rootnode->leaf = $test_spec['leaf']; $treeMenu->rootnode->text = $test_spec['text']; $treeMenu->rootnode->position = $test_spec['position']; $treeMenu->rootnode->href = $test_spec['href']; if (!is_null($menustring)) { // Change key ('childNodes') to the one required by Ext JS tree. if (isset($test_spec['childNodes'])) { $menustring = str_ireplace('childNodes', 'children', json_encode($test_spec['childNodes'])); } // Remove null elements (Ext JS tree do not like it ). // :null happens on -> "children":null,"text" that must become "children":[],"text" // $menustring = str_ireplace(array(':null',',null','null,'),array(':[]','',''), $menustring); $menustring = str_ireplace(array(':null', ',null', 'null,', 'null'), array(':[]', '', '', ''), $menustring); } $treeMenu->menustring = $menustring; return array($treeMenu, $keys); }