function execTree(&$dbHandler, &$menuUrl, $context, $objFilters, $objOptions) { $chronos[] = 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; $tck_map = null; $idx = 0; $testCaseQty = 0; $testCaseSet = null; $keyword_id = 0; $keywordsFilterType = 'Or'; if (property_exists($objFilters, 'filter_keywords') && !is_null($objFilters->filter_keywords)) { $keyword_id = $objFilters->filter_keywords; $keywordsFilterType = $objFilters->filter_keywords_filter_type; } $renderTreeNodeOpt = array(); $renderTreeNodeOpt['showTestCaseID'] = config_get('treemenu_show_testcase_id'); list($filters, $options, $renderTreeNodeOpt['showTestSuiteContents'], $renderTreeNodeOpt['useCounters'], $renderTreeNodeOpt['useColors'], $colorBySelectedBuild) = initExecTree($objFilters, $objOptions); $renderTreeNodeOpt['showTestCaseExecStatus'] = $options['showTestCaseExecStatus']; if (property_exists($objOptions, 'actionJS')) { if (isset($objOptions->actionJS['testproject'])) { $renderTreeNodeOpt['actionJS']['testproject'] = $objOptions->actionJS['testproject']; } } $tplan_mgr = new testplan($dbHandler); $tproject_mgr = new testproject($dbHandler); $tcase_node_type = $tplan_mgr->tree_manager->node_descr_id['testcase']; $hash_descr_id = $tplan_mgr->tree_manager->get_available_node_types(); $hash_id_descr = array_flip($hash_descr_id); $tcase_prefix = $tproject_mgr->getTestCasePrefix($context['tproject_id']) . $glueChar; // 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' => $tplan_mgr->tree_manager->node_descr_id['testsuite'], 'order_cfg' => array("type" => 'exec_order', "tplan_id" => $context['tplan_id'])); $my['filters'] = array('exclude_node_types' => array('testplan' => 'exclude_me', 'requirement_spec' => 'exclude_me', 'requirement' => 'exclude_me'), 'exclude_children_of' => array('testcase' => 'exclude_my_children', 'requirement_spec' => 'exclude_my_children')); // added for filtering by toplevel testsuite 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; } // Document why this is needed, please $test_spec = $tplan_mgr->getSkeleton($context['tplan_id'], $context['tproject_id'], $my['filters'], $my['options']); $test_spec['name'] = $context['tproject_name'] . " / " . $context['tplan_name']; // To be discussed $test_spec['id'] = $context['tproject_id']; $test_spec['node_type_id'] = $hash_descr_id['testproject']; $test_spec['node_type'] = 'testproject'; $map_node_tccount = array(); $tplan_tcases = null; $linkedTestCasesSet = null; 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->getLinkedForExecTree($context['tplan_id'], $filters, $options))) { $kmethod = "fetchRowsIntoMap"; if (is_array($sql2do)) { if ($filters['keyword_filter_type'] == 'And') { $kmethod = "fetchRowsIntoMapAddRC"; $unionClause = " UNION ALL "; } else { $kmethod = "fetchRowsIntoMap"; $unionClause = ' UNION '; } $sql2run = $sql2do['exec'] . $unionClause . $sql2do['not_run']; } else { $sql2run = $sql2do; } $tplan_tcases = $setTestCaseStatus = $dbHandler->{$kmethod}($sql2run, 'tcase_id'); } } if (!is_null($tplan_tcases)) { // 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($context['tplan_id'], $tplan_tcases, $objFilters, $tplan_mgr, $resultsCfg['status_code']); } if (isset($my['filters']['filter_custom_fields']) && isset($test_spec['childNodes'])) { // need to separate cf 4 design that cf 4 testplan_design. // Here we ONLY use cf 4 design $cfx = cfForDesign($dbHandler, $my['filters']['filter_custom_fields']); if (!is_null($cfx)) { $test_spec['childNodes'] = filter_by_cf_values($dbHandler, $test_spec['childNodes'], $cfx, $hash_descr_id); } } // ATTENTION: sometimes we use $my['options'], other $options $pnOptions = array('hideTestCases' => $options['hideTestCases'], 'viewType' => 'executionTree'); $pnFilters = null; $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]; } } else { $tplan_tcases = array(); $test_spec['childNodes'][0] = null; $testcase_counters = helperInitCounters(); foreach ($testcase_counters as $key => $value) { $test_spec[$key] = $testcase_counters[$key]; } } $renderTreeNodeOpt['hideTestCases'] = $options['hideTestCases']; $renderTreeNodeOpt['tc_action_enabled'] = 1; // CRITIC: renderExecTreeNode() WILL MODIFY $tplan_tcases, can empty it completely $linkedTestCasesSet = array_keys((array) $tplan_tcases); $menustring = renderExecTreeNode(1, $test_spec, $tplan_tcases, $hash_id_descr, $menuUrl, $tcase_prefix, $renderTreeNodeOpt); } $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, $linkedTestCasesSet); }