/** * Class constructor * * @param object [ref] $db the database connection * @param string $attachmentTableName the foreign key table name to store the attachments */ function __construct(&$db, $attachmentTableName) { tlObjectWithDB::__construct($db); $this->attachmentRepository = tlAttachmentRepository::create($this->db); $this->attachmentTableName = $attachmentTableName; }
* * @filesource attachmentdownload.php * * @internal revisions * @since 1.9.13 * */ @ob_end_clean(); require_once '../../config.inc.php'; require_once '../functions/common.php'; require_once '../functions/attachments.inc.php'; // This way can be called without _SESSION, this is useful for reports testlinkInitPage($db, false, true); $args = init_args(); if ($args->id) { $attachmentRepository = tlAttachmentRepository::create($db); $attachmentInfo = $attachmentRepository->getAttachmentInfo($args->id); // if ($attachmentInfo) if ($attachmentInfo && ($args->skipCheck || checkAttachmentID($db, $args->id, $attachmentInfo))) { $content = $attachmentRepository->getAttachmentContent($args->id, $attachmentInfo); if ($content != "") { @ob_end_clean(); header('Pragma: public'); header("Cache-Control: "); if (!(isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on" && preg_match("/MSIE/", $_SERVER["HTTP_USER_AGENT"]))) { header('Pragma: no-cache'); } header('Content-Type: ' . $attachmentInfo['file_type']); header('Content-Length: ' . $attachmentInfo['file_size']); header("Content-Disposition: inline; filename=\"{$attachmentInfo['file_name']}\""); header("Content-Description: Download Data");
/** * */ function deleteAttachment(&$dbHandler, $fileID, $checkOnSession = true) { $repo = tlAttachmentRepository::create($dbHandler); $info = $repo->getAttachmentInfo($fileID); if ($info) { $doIt = true; if ($checkOnSession) { $doIt = checkAttachmentID($dbHandler, $fileID, $info); } if ($doIt) { if ($repo->deleteAttachment($fileID, $info)) { logAuditEvent(TLS("audit_attachment_deleted", $info['title']), "DELETE", $fileID, "attachments"); } } } }
function createManagers($dbHandler, $tprojectID) { $is = new stdClass(); $is->tree = new tree($dbHandler); $is->tproject = new testproject($dbHandler); $is->tsuite = new testsuite($dbHandler); $is->tplan = new testplan($dbHandler); $is->tcase = new testcase($dbHandler); $is->req = new requirement_mgr($dbHandler); $is->repository = tlAttachmentRepository::create($dbHandler); $is->exec_cfield = new exec_cfield_mgr($dbHandler, $tprojectID); return $is; }
/** * Uploads an attachment for specified table. You must specify the table that * the attachment is connected (nodes_hierarchy, builds, etc) and the foreign * key id in this table. * * The attachment content must be Base64 encoded by the client before sending it. * * @param struct $args * @param string $args["devKey"] Developer key * @param int $args["fkid"] The Attachment Foreign Key ID * @param string $args["fktable"] The Attachment Foreign Key Table * @param string $args["title"] (Optional) The title of the Attachment * @param string $args["description"] (Optional) The description of the Attachment * @param string $args["filename"] The file name of the Attachment (e.g.:notes.txt) * @param string $args["filetype"] The file type of the Attachment (e.g.: text/plain) * @param string $args["content"] The content (Base64 encoded) of the Attachment * * @since 1.9beta6 * @return mixed $resultInfo an array containing the fk_id, fk_table, title, * description, file_name, file_size and file_type. If any errors occur it * returns the erros map. */ public function uploadAttachment($args, $messagePrefix = '', $setArgs = true) { $resultInfo = array(); if ($setArgs) { $this->_setArgs($args); } $msg_prefix = $messagePrefix == '' ? "(" . __FUNCTION__ . ") - " : $messagePrefix; $checkFunctions = array(); // TODO: please, somebody review if this is valid. I added this property // to avoid the upload method of double authenticating the user. // Otherwise, when uploadTestCaseAttachment was called, for instante, it // would authenticate, check if the nodes_hierarchy is type TestCase // and then call uploadAttachment that would, authenticate again. // What do you think? if (!$this->authenticated) { $checkFunctions[] = 'authenticate'; } // check if : // TL has attachments enabled // provided FK is valid // attachment info is ok $checkFunctions[] = 'isAttachmentEnabled'; $checkFunctions[] = 'checkForeignKey'; $checkFunctions[] = 'checkUploadAttachmentRequest'; $statusOk = $this->_runChecks($checkFunctions, $msg_prefix); if ($statusOk) { $fkId = $this->args[self::$foreignKeyIdParamName]; $fkTable = $this->args[self::$foreignKeyTableNameParamName]; $title = $this->args[self::$titleParamName]; // creates a temp file and returns an array with size and tmp_name $fInfo = $this->createAttachmentTempFile(); if (!$fInfo) { // Error creating attachment temp file. Ask user to check temp dir // settings in php.ini and security and rights of this dir. $msg = $msg_prefix . ATTACH_TEMP_FILE_CREATION_ERROR_STR; $this->errors[] = new IXR_ERROR(ATTACH_TEMP_FILE_CREATION_ERROR, $msg); $statusOk = false; } else { // The values have already been validated in the method // checkUploadAttachmentRequest() $fInfo['name'] = $args[self::$fileNameParamName]; $fInfo['type'] = $args[self::$fileTypeParamName]; $attachmentRepository = tlAttachmentRepository::create($this->dbObj); $uploadedFile = $attachmentRepository->insertAttachment($fkId, $fkTable, $title, $fInfo); if (!$uploadedFile) { $msg = $msg_prefix . ATTACH_DB_WRITE_ERROR_STR; $this->errors[] = new IXR_ERROR(ATTACH_DB_WRITE_ERROR, $msg); $statusOk = false; } else { // We are returning some data that the user originally sent. // Perhaps we could return only new data, like the file size? $resultInfo['fk_id'] = $args[self::$foreignKeyIdParamName]; $resultInfo['fk_table'] = $args[self::$foreignKeyTableNameParamName]; $resultInfo['title'] = $args[self::$titleParamName]; $resultInfo['description'] = $args[self::$descriptionParamName]; $resultInfo['file_name'] = $args[self::$fileNameParamName]; // It would be nice have all info available in db // $resultInfo['file_path'] = $args[""]; // we could also return the tmp_name, but would it be useful? $resultInfo['file_size'] = $fInfo['size']; $resultInfo['file_type'] = $args[self::$fileTypeParamName]; } } } return $statusOk ? $resultInfo : $this->errors; }
/** * Gets attachments for specified test case. * The attachment file content is Base64 encoded. To save the file to disk in client, * Base64 decode the content and write file in binary mode. * * @param struct $args * @param string $args["devKey"] Developer key * @param int $args["testcaseid"]: optional, if does not is present * testcaseexternalid must be present * * @param int $args["testcaseexternalid"]: optional, if does not is present * testcaseid must be present * * @return mixed $resultInfo */ public function getTestCaseAttachments($args) { $this->_setArgs($args); $attachments = null; $checkFunctions = array('authenticate', 'checkTestCaseIdentity'); $status_ok = $this->_runChecks($checkFunctions) && $this->userHasRight("mgt_view_tc"); if ($status_ok) { $tcase_id = $this->args[self::$testCaseIDParamName]; $attachmentRepository = tlAttachmentRepository::create($this->dbObj); $attachmentInfos = $attachmentRepository->getAttachmentInfosFor($tcase_id, "nodes_hierarchy"); if ($attachmentInfos) { foreach ($attachmentInfos as $attachmentInfo) { $aID = $attachmentInfo["id"]; $content = $attachmentRepository->getAttachmentContent($aID, $attachmentInfo); if ($content != null) { $attachments[$aID]["id"] = $aID; $attachments[$aID]["name"] = $attachmentInfo["file_name"]; $attachments[$aID]["file_type"] = $attachmentInfo["file_type"]; $attachments[$aID]["title"] = $attachmentInfo["title"]; $attachments[$aID]["date_added"] = $attachmentInfo["date_added"]; $attachments[$aID]["content"] = base64_encode($content); } } } } return $status_ok ? $attachments : $this->errors; }
if (trim($gui->tableName) == 'executions') { $opt['allow_empty_title'] = true; } $l2d = count($fInfo); new dBug($fInfo); for ($fdx = 0; $fdx <= $l2d; $fdx++) { $fSize = isset($fInfo['size'][$fdx]) ? $fInfo['size'][$fdx] : 0; $fTmpName = isset($fInfo['tmp_name'][$fdx]) ? $fInfo['tmp_name'][$fdx] : ''; $fin = array(); $fin['size'] = $fSize; $fin['tmp_name'] = $fTmpName; $fin['type'] = $fInfo['type'][$fdx]; $fin['name'] = $fInfo['name'][$fdx]; $fin['error'] = $fInfo['error'][$fdx]; if ($fSize && $fTmpName != "") { $docRepo = tlAttachmentRepository::create($db); $gui->uploaded = $docRepo->insertAttachment($id, $gui->tableName, $args->title, $fin, $opt); if ($gui->uploaded) { logAuditEvent(TLS("audit_attachment_created", $args->title, $fin['name']), "CREATE", $id, "attachments"); } } else { $gui->msg = getFileUploadErrorMessage($fin); } } } } else { $_SESSION['s_upload_tableName'] = $args->tableName; $_SESSION['s_upload_id'] = $args->id; } $smarty = new TLSmarty(); $smarty->assign('gui', $gui);
/** * render Test Case content for generated documents * * @param $integer db DB connection identifier * @return string generated html code * * @internal revisions */ function renderTestCaseForPrinting(&$db, &$node, &$options, $env, $context, $indentLevel) { static $req_mgr; static $tc_mgr; static $build_mgr; static $tplan_mgr; static $tplan_urgency; static $labels; static $tcase_prefix; static $userMap = array(); static $cfg; static $tables = null; static $force = null; static $bugInterfaceOn = false; static $its; static $buildCfields; static $statusL10N; static $docRepo; static $st; $code = null; $tcInfo = null; $tcResultInfo = null; $tcase_pieces = null; $id = $node['id']; $level = $indentLevel; $prefix = isset($context['prefix']) ? $context['prefix'] : null; $tplan_id = isset($context['tplan_id']) ? $context['tplan_id'] : 0; $tprojectID = isset($context['tproject_id']) ? $context['tproject_id'] : 0; $platform_id = isset($context['platform_id']) ? $context['platform_id'] : 0; $build_id = isset($context['build_id']) ? $context['build_id'] : 0; // init static elements if (!$tables) { $st = new stdClass(); $tables = tlDBObject::getDBTables(array('executions', 'builds', 'execution_tcsteps')); $tc_mgr = new testcase($db); $tplan_urgency = new testPlanUrgency($db); $build_mgr = new build_mgr($db); $tplan_mgr = new testplan($db); $req_mgr = new requirement_mgr($db); list($cfg, $labels) = initRenderTestCaseCfg($tc_mgr, $options); if (!is_null($prefix)) { $tcase_prefix = $prefix; } else { list($tcase_prefix, $dummy) = $tc_mgr->getPrefix($id); } $tcase_prefix .= $cfg['testcase']->glue_character; $force['displayVersion'] = isset($options['displayVersion']) ? $options['displayVersion'] : false; $force['displayLastEdit'] = isset($options['displayLastEdit']) ? $options['displayLastEdit'] : false; $its = null; $tproject_mgr = new testproject($db); $info = $tproject_mgr->get_by_id($tprojectID); $bugInterfaceOn = $info['issue_tracker_enabled']; if ($info['issue_tracker_enabled']) { $it_mgr = new tlIssueTracker($db); $its = $it_mgr->getInterfaceObject($tprojectID); unset($it_mgr); } $statusL10N = null; foreach ($cfg['results']['code_status'] as $vc => $vstat) { if (isset($cfg['results']['status_label_for_exec_ui'][$vstat])) { $statusL10N[$vc] = lang_get($cfg['results']['status_label_for_exec_ui'][$vstat]); } } $docRepo = tlAttachmentRepository::create($db); $st->locationFilters = $tc_mgr->buildCFLocationMap(); // change table style in case of single TC printing to not be indented $st->table_style = ""; if (isset($options['docType']) && $options['docType'] == SINGLE_TESTCASE) { $st->table_style = 'style="margin-left: 0;"'; } $st->cfieldFormatting = array('label_css_style' => '', 'add_table' => false, 'value_css_style' => ' colspan = "' . ($cfg['tableColspan'] - 1) . '" '); $info = null; } /** * @TODO THIS IS NOT THE WAY TO DO THIS IS ABSOLUTELY WRONG AND MUST BE REFACTORED, * using existent methods - franciscom - 20090329 * Need to get CF with execution scope */ $exec_info = null; $getByID['filters'] = null; $opt = array(); $opt['step_exec_notes'] = isset($options['step_exec_notes']) && $options['step_exec_notes']; $opt['step_exec_status'] = isset($options['step_exec_status']) && $options['step_exec_status']; switch ($options["docType"]) { case DOC_TEST_SPEC: $getByID['tcversion_id'] = testcase::LATEST_VERSION; $getExecutions = false; break; case SINGLE_TESTCASE: $getByID['tcversion_id'] = $node['tcversion_id']; $getExecutions = $options['passfail'] || $options['notes'] || $opt['step_exec_notes'] || $opt['step_exec_status']; break; default: $getByID['tcversion_id'] = $node['tcversion_id']; $getExecutions = $options['cfields'] || $options['passfail'] || $options['notes'] || $opt['step_exec_notes'] || $opt['step_exec_status']; break; } if ($getExecutions) { // Thanks to Evelyn from Cortado, have found a very old issue never reported. // 1. create TC-1A VERSION 1 // 2. add to test plan and execute FAILED ON BUILD 1 // 3. Request Test Report (Test Plan EXECUTION REPORT). // You will get spec for VERSION 1 and result for VERSION 1 - OK cool! // 4. create VERSION 2 // 5. update linked Test Case Versions // 6. do nothing more than repeat step 3 // without this fix you will get // You will get spec for VERSION 2 and result for VERSION 1 - Hmmm // and in addition is not clear that execution was on VERSION 1 . No GOOD!! // // HOW has been fixed ? // Getting info about THE CURRENT LINKED test case version and looking for // exec info for this. // // ATTENTION: THIS IS OK ONLY WHEN BUILD ID is not provided // // // Get Linked test case version $linkedItem = $tplan_mgr->getLinkInfo($tplan_id, $id, $platform_id); $sql = " SELECT E.id AS execution_id, E.status, E.execution_ts, E.tester_id," . " E.notes, E.build_id, E.tcversion_id,E.tcversion_number,E.testplan_id," . " E.execution_type, E.execution_duration, " . " B.name AS build_name " . " FROM {$tables['executions']} E " . " JOIN {$tables['builds']} B ON B.id = E.build_id " . " WHERE 1 = 1 "; if (isset($context['exec_id'])) { $sql .= " AND E.id=" . intval($context['exec_id']); } else { $sql .= " AND E.testplan_id = " . intval($tplan_id) . " AND E.platform_id = " . intval($platform_id) . " AND E.tcversion_id = " . intval($linkedItem[0]['tcversion_id']); if ($build_id > 0) { $sql .= " AND E.build_id = " . intval($build_id); } else { // We are looking for LATEST EXECUTION of CURRENT LINKED test case version $sql .= " AND E.tcversion_number=" . intval($linkedItem[0]['version']); } $sql .= " ORDER BY execution_id DESC"; } $exec_info = $db->get_recordset($sql, null, 1); $getByID['tcversion_id'] = $linkedItem[0]['tcversion_id']; $getByID['filters'] = null; $linkedItem = null; if (!is_null($exec_info)) { $getByID['tcversion_id'] = null; $getByID['filters'] = array('version_number' => $exec_info[0]['tcversion_number']); if (isset($options['build_cfields']) && $options['build_cfields']) { if (!isset($buildCfields[$exec_info[0]['build_id']])) { $buildCfields[$exec_info[0]['build_id']] = $build_mgr->html_table_of_custom_field_values($exec_info[0]['build_id'], $tprojectID); } } } } $tcInfo = $tc_mgr->get_by_id($id, $getByID['tcversion_id'], $getByID['filters'], array('renderGhost' => true, 'renderImageInline' => true)); if ($tcInfo) { $tcInfo = $tcInfo[0]; } $external_id = $tcase_prefix . $tcInfo['tc_external_id']; $name = htmlspecialchars($node['name']); $cfields = array('specScope' => null, 'execScope' => null); if ($options['cfields']) { // Get custom fields that has specification scope // Custom Field values at Test Case VERSION Level foreach ($st->locationFilters as $fkey => $fvalue) { $cfields['specScope'][$fkey] = $tc_mgr->html_table_of_custom_field_values($id, 'design', $fvalue, null, $tplan_id, $tprojectID, $st->cfieldFormatting, $tcInfo['id']); } if (!is_null($exec_info)) { $cfields['execScope'] = $tc_mgr->html_table_of_custom_field_values($tcInfo['id'], 'execution', null, $exec_info[0]['execution_id'], $tplan_id, $tprojectID, $st->cfieldFormatting); } } if ($options['toc']) { // EXTERNAL ID added $options['tocCode'] .= '<p style="padding-left: ' . 15 * $level . 'px;"><a href="#' . prefixToHTMLID('tc' . $id) . '">' . htmlspecialchars($external_id) . ": " . $name . '</a></p>'; $code .= '<a name="' . prefixToHTMLID('tc' . $id) . '"></a>'; } $code .= '<p> </p><div> <table class="tc" width="90%" ' . $st->table_style . '>'; $code .= '<tr><th colspan="' . $cfg['tableColspan'] . '">' . $labels['test_case'] . " " . htmlspecialchars($external_id) . ": " . $name; // add test case version switch ($env->reportType) { case DOC_TEST_PLAN_DESIGN: $version_number = isset($node['version']) ? $node['version'] : $tcInfo['version']; break; case DOC_TEST_PLAN_EXECUTION: case DOC_TEST_PLAN_EXECUTION_ON_BUILD: $version_number = $tcInfo['version']; break; default: $version_number = $tcInfo['version']; break; } if ($cfg['doc']->tc_version_enabled || $force['displayVersion']) { $code .= ' <span style="font-size: 80%;">' . $cfg['gui']->role_separator_open . $labels['version'] . $cfg['gui']->title_separator_1 . $version_number . $cfg['gui']->role_separator_close . '</span>'; } $code .= "</th></tr>\n"; if ($options['author']) { $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . '<span class="label">' . $labels['author'] . ':</span></td>' . '<td colspan="' . ($cfg['tableColspan'] - 1) . '">' . gendocGetUserName($db, $tcInfo['author_id']); if (isset($options['displayDates']) && $options['displayDates']) { $dummy = null; $code .= ' - ' . localize_dateOrTimeStamp(null, $dummy, 'timestamp_format', $tcInfo['creation_ts']); } $code .= "</td></tr>\n"; if ($tcInfo['updater_id'] > 0) { // add updater if available and differs from author OR forced if ($force['displayLastEdit'] > 0 || $tcInfo['updater_id'] != $tcInfo['author_id']) { $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . '<span class="label">' . $labels['last_edit'] . ':</span></td>' . '<td colspan="' . ($cfg['tableColspan'] - 1) . '">' . gendocGetUserName($db, $tcInfo['updater_id']); if (isset($options['displayDates']) && $options['displayDates']) { $dummy = null; $code .= ' - ' . localize_dateOrTimeStamp(null, $dummy, 'timestamp_format', $tcInfo['modification_ts']); } $code .= "</td></tr>\n"; } } } if ($options['body'] || $options['summary']) { $tcase_pieces = array('summary'); } if ($options['body']) { $tcase_pieces[] = 'preconditions'; } if ($options['body'] || $options['step_exec_notes'] || $options['step_exec_status']) { $tcase_pieces[] = 'steps'; } if (!is_null($tcase_pieces)) { // Check user rights in order to understand if can delete attachments here // function hasRight(&$db,$roleQuestion,$tprojectID = null,$tplanID = null,$getAccess=false) // $tplan_id = isset($context['tplan_id']) ? $context['tplan_id'] : 0; // $tprojectID = isset($context['tproject_id']) ? $context['tproject_id'] : 0; $canManageAttachments = false; if (isset($context['user']) && !is_null($context['user'])) { $canManageAttachments = $context['user']->hasRight($db, 'testplan_execute', $tprojectID, $tplan_id); } // Multiple Test Case Steps Feature foreach ($tcase_pieces as $key) { if ($key == 'steps') { if (isset($cfields['specScope']['before_steps_results'])) { $code .= $cfields['specScope']['before_steps_results']; } if (!is_null($tcInfo[$key]) && $tcInfo[$key] != '') { $td_colspan = 3; $code .= '<tr>' . '<td><span class="label">' . $labels['step_number'] . ':</span></td>' . '<td><span class="label">' . $labels['step_actions'] . ':</span></td>' . '<td><span class="label">' . $labels['expected_results'] . ':</span></td>'; $sxni = null; if ($opt['step_exec_notes'] || $opt['step_exec_status']) { $sxni = $tc_mgr->getStepsExecInfo($exec_info[0]['execution_id']); if ($opt['step_exec_notes']) { $td_colspan++; $code .= '<td><span class="label">' . $labels['step_exec_notes'] . ':</span></td>'; } if ($opt['step_exec_status']) { $td_colspan++; $code .= '<td><span class="label">' . $labels['step_exec_status'] . ':</span></td>'; } } $code .= '</tr>'; $loop2do = count($tcInfo[$key]); for ($ydx = 0; $ydx < $loop2do; $ydx++) { $code .= '<tr>' . '<td width="5">' . $tcInfo[$key][$ydx]['step_number'] . '</td>' . '<td>' . $tcInfo[$key][$ydx]['actions'] . '</td>' . '<td>' . $tcInfo[$key][$ydx]['expected_results'] . '</td>'; $nike = !is_null($sxni) && isset($sxni[$tcInfo[$key][$ydx]['id']]) && !is_null($sxni[$tcInfo[$key][$ydx]['id']]); if ($opt['step_exec_notes']) { $code .= '<td>'; if ($nike) { $code .= $sxni[$tcInfo[$key][$ydx]['id']]['notes']; } $code .= '</td>'; } if ($opt['step_exec_status']) { $code .= '<td>'; if ($nike) { $code .= $statusL10N[$sxni[$tcInfo[$key][$ydx]['id']]['status']]; } $code .= '</td>'; } $code .= '</tr>'; // Attachment management if ($getExecutions) { if (isset($sxni[$tcInfo[$key][$ydx]['id']])) { $attachInfo = getAttachmentInfos($docRepo, $sxni[$tcInfo[$key][$ydx]['id']]['id'], $tables['execution_tcsteps'], true, 1); if (!is_null($attachInfo)) { $code .= '<tr><td colspan="' . $td_colspan . '">'; $code .= '<b>' . $labels['exec_attachments'] . '</b><br>'; foreach ($attachInfo as $fitem) { $code .= '<form method="POST" name="fda' . $fitem['id'] . '" ' . ' id="fda' . $fitem['id'] . "' " . ' action="' . $env->base_href . 'lib/execute/execPrint.php">'; $code .= '<input type="hidden" name="id" value="' . intval($context['exec_id']) . '">'; $code .= '<input type="hidden" name="deleteAttachmentID" value="' . intval($fitem['id']) . '">'; if ($fitem['is_image']) { $code .= "<li>" . htmlspecialchars($fitem['file_name']) . "</li>"; $code .= '<li>' . '<img src="' . $env->base_href . 'lib/attachments/attachmentdownload.php?skipCheck=1&id=' . $fitem['id'] . '">'; } else { $code .= '<li>' . '<a href="' . $env->base_href . 'lib/attachments/attachmentdownload.php?skipCheck=1&id=' . $fitem['id'] . '" ' . ' target="#blank" > ' . htmlspecialchars($fitem['file_name']) . '</a>'; } $code .= '<input type="image" alt="' . $labels['alt_delete_attachment'] . '"' . 'src="' . $env->base_href . TL_THEME_IMG_DIR . 'trash.png"></li></form>'; } $code .= '</td></tr>'; } } } // $getExecutions } } } else { // disable the field if it's empty if ($tcInfo[$key] != '') { $code .= '<tr><td colspan="' . $cfg['tableColspan'] . '"><span class="label">' . $labels[$key] . ':</span><br />' . $tcInfo[$key] . "</td></tr>"; } } } } $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . '<span class="label">' . $labels['execution_type'] . ':</span></td>' . '<td colspan="' . ($cfg['tableColspan'] - 1) . '">'; // This is what have been choosen DURING DESIGN, but may be we can choose at DESIGN // manual and the execute AUTO, or may be choose AUTO and execute MANUAL. // After report on MANTIS, seems that we need to provide in output two values: // DESIGN execution type // EXECUTION execution type switch ($tcInfo['execution_type']) { case TESTCASE_EXECUTION_TYPE_AUTO: $code .= $labels['execution_type_auto']; break; case TESTCASE_EXECUTION_TYPE_MANUAL: default: $code .= $labels['execution_type_manual']; break; } $code .= "</td></tr>\n"; // $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . '<span class="label">' . $labels['estimated_execution_duration'] . ':</span></td>' . '<td colspan="' . ($cfg['tableColspan'] - 1) . '">' . $tcInfo['estimated_exec_duration']; $code .= "</td></tr>\n"; if (isset($options['importance']) && $options['importance']) { $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . '<span class="label">' . $labels['importance'] . ':</span></td>' . '<td colspan="' . ($cfg['tableColspan'] - 1) . '">' . $cfg['importance'][$tcInfo['importance']]; $code .= "</td></tr>\n"; } // print priority when printing test plan if (isset($options['priority']) && $options['priority']) { // Get priority of this tc version for this test plan by using testplanUrgency class. // Is there maybe a better method than this one? $filters = array('tcversion_id' => $tcInfo['id']); $opt = array('details' => 'tcversion'); $prio_info = $tplan_urgency->getPriority($tplan_id, $filters, $opt); $prio = $prio_info[$tcInfo['id']]['priority_level']; $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . '<span class="label">' . $labels['priority'] . ':</span></td>' . '<td colspan="' . ($cfg['tableColspan'] - 1) . '">' . $cfg['priority'][$prio]; $code .= "</td></tr>\n"; } // Spacer $code .= '<tr><td colspan="' . $cfg['tableColspan'] . '">' . "</td></tr>"; $code .= $cfields['specScope']['standard_location'] . $cfields['execScope']; // $cfields = null; $prio_info = null; // $code = null; // 20140813 $relSet = $tc_mgr->getRelations($id); if (!is_null($relSet['relations'])) { // $fx = str_repeat(' ',5); // MAGIC allowed $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top"><span class="label">' . $labels['relations'] . '</span></td>'; $code .= '<td>'; for ($rdx = 0; $rdx < $relSet['num_relations']; $rdx++) { if ($relSet['relations'][$rdx]['source_id'] == $id) { $ak = 'source_localized'; } else { $ak = 'destination_localized'; } $code .= htmlspecialchars($relSet['relations'][$rdx][$ak]) . ' - ' . htmlspecialchars($relSet['relations'][$rdx]['related_tcase']['fullExternalID']) . ':' . htmlspecialchars($relSet['relations'][$rdx]['related_tcase']['name']) . '<br>'; } $code .= '</td></tr>'; } $relSet = null; // collect REQ for TC if ($options['requirement']) { $requirements = $req_mgr->get_all_for_tcase($id); $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top"><span class="label">' . $labels['reqs'] . '</span>'; $code .= '<td colspan="' . ($cfg['tableColspan'] - 1) . '">'; if (sizeof($requirements)) { foreach ($requirements as $req) { $code .= htmlspecialchars($req['req_doc_id'] . ": " . $req['title']) . "<br />"; } } else { $code .= ' ' . $labels['none'] . '<br />'; } $code .= "</td></tr>\n"; } $requirements = null; // collect keywords for TC if ($options['keyword']) { $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top"><span class="label">' . $labels['keywords'] . ':</span>'; $code .= '<td colspan="' . ($cfg['tableColspan'] - 1) . '">'; $kwSet = $tc_mgr->getKeywords($id, null, array('fields' => 'keyword_id,keywords.keyword')); if (sizeof($kwSet)) { foreach ($kwSet as $kw) { $code .= htmlspecialchars($kw['keyword']) . "<br />"; } } else { $code .= ' ' . $labels['none'] . '<br>'; } $code .= "</td></tr>\n"; } $kwSet = null; // Attachments $attachSet = (array) $tc_mgr->getAttachmentInfos($id); if (count($attachSet) > 0) { $code .= '<tr><td> <span class="label">' . $labels['attached_files'] . '</span></td>'; $code .= '<td colspan="' . ($cfg['tableColspan'] - 2) . '"><ul>'; foreach ($attachSet as $item) { $fname = ""; if ($item['title']) { $fname .= htmlspecialchars($item['title']) . " : "; } $fname .= htmlspecialchars($item['file_name']); $code .= "<li>{$fname}</li>"; if ($item['is_image']) { $code .= '<li>' . '<img src="' . $env->base_href . 'lib/attachments/attachmentdownload.php?skipCheck=1&id=' . $item['id'] . '"> </li>'; } else { $code .= '<li>' . '<a href="' . $env->base_href . 'lib/attachments/attachmentdownload.php?skipCheck=1&id=' . $item['id'] . '" ' . ' target="#blank" > ' . htmlspecialchars($item['file_name']) . '</a></li>'; } } $code .= "</ul></td></tr>"; } $attachSet = null; // generate test results data for test report if ($options['passfail']) { $tsp = $cfg['tableColspan'] - 1; $code .= '<tr style="' . "font-weight: bold;background: #EEE;text-align: left;" . '">' . '<td width="' . $cfg['firstColWidth'] . '" valign="top">' . $labels['execution_details'] . '</td>' . '<td colspan="' . $tsp . '">' . " " . "</b></td></tr>\n"; $bn = ''; switch ($env->reportType) { case DOC_TEST_PLAN_EXECUTION_ON_BUILD: $ib = $build_mgr->get_by_id($build_id); $bn = htmlspecialchars($ib['name']); break; case DOC_TEST_PLAN_EXECUTION: if ($exec_info) { $bn = htmlspecialchars($exec_info[0]['build_name']); } break; } if ($bn != '') { $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . $labels['build'] . '</td>' . '<td ' . $tsp . '>' . $bn . "</b></td></tr>\n"; } if (isset($node['assigned_to'])) { $crew = explode(',', $node['assigned_to']); $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . $labels['assigned_to'] . '</td>' . '<td colspan="' . $tsp . '">'; $xdx = 0; foreach ($crew as $mm) { if ($xdx != 0) { $code .= ','; } $xdx = -1; echo $mm . '<br>'; $code .= gendocGetUserName($db, $mm); } $code .= "</td></tr>\n"; } if ($exec_info) { $settings['cfg'] = $cfg; $settings['lbl'] = $labels; $settings['opt'] = array('show_notes' => $options['notes']); $settings['colspan'] = $cfg['tableColspan'] - 1; $code .= buildTestExecResults($db, $its, $exec_info, $settings, $buildCfields); // Get Execution Attachments $execAttachInfo = getAttachmentInfos($docRepo, $exec_info[0]['execution_id'], $tables['executions'], true, 1); if (!is_null($execAttachInfo)) { $code .= '<tr><td colspan="' . $cfg['tableColspan'] . '">'; $code .= '<b>' . $labels['exec_attachments'] . '</b><br>'; foreach ($execAttachInfo as $fitem) { if ($fitem['is_image']) { $code .= "<li>" . htmlspecialchars($fitem['file_name']) . "</li>"; $code .= '<li>' . '<img src="' . $env->base_href . 'lib/attachments/attachmentdownload.php?skipCheck=1&id=' . $fitem['id'] . '"> </li>'; } else { $code .= '<li>' . '<a href="' . $env->base_href . 'lib/attachments/attachmentdownload.php?skipCheck=1&id=' . $fitem['id'] . '" ' . ' target="#blank" > ' . htmlspecialchars($fitem['file_name']) . '</a></li>'; } } $code .= '</td></tr>'; } } else { $code .= '<tr><td width="' . $cfg['firstColWidth'] . '" valign="top">' . '<span class="label">' . $labels['report_exec_result'] . '</span></td>' . '<td colspan="' . ($cfg['tableColspan'] - 1) . '"><b>' . $labels["test_status_not_run"] . "</b></td></tr>\n"; } $execAttachInfo = null; $exec_info = null; } $code .= "</table>\n</div>\n"; return $code; }
function getAttachments(&$dbHandler, &$execSet) { $attachmentMgr = tlAttachmentRepository::create($dbHandler); $att = null; $tcv2loop = array_keys($execSet); foreach ($tcv2loop as $tcvid) { $execQty = count($execSet[$tcvid]); for ($idx = 0; $idx < $execQty; $idx++) { $exec_id = $execSet[$tcvid][$idx]['execution_id']; $items = getAttachmentInfos($attachmentMgr, $exec_id, 'executions', true, 1); if ($items) { $att[$exec_id] = $items; } } } return $att; }
/** * write execution result to DB * * @param resource &$db reference to database handler * @param obj &$exec_signature object with tproject_id,tplan_id,build_id,platform_id,user_id * * @internal revisions * */ function write_execution(&$db, &$exec_signature, &$exec_data, &$issueTracker) { static $docRepo; if (is_null($docRepo)) { $docRepo = tlAttachmentRepository::create($db); } $executions_table = DB_TABLE_PREFIX . 'executions'; $resultsCfg = config_get('results'); $execCfg = config_get('exec_cfg'); $db_now = $db->db_now(); $cfield_mgr = new cfield_mgr($db); $cf_prefix = $cfield_mgr->get_name_prefix(); $len_cfp = tlStringLen($cf_prefix); $cf_nodeid_pos = 4; $bulk_notes = ''; $ENABLED = 1; $cf_map = $cfield_mgr->get_linked_cfields_at_execution($exec_signature->tproject_id, $ENABLED, 'testcase'); $has_custom_fields = is_null($cf_map) ? 0 : 1; // extract custom fields id. $map_nodeid_array_cfnames = null; foreach ($exec_data as $input_name => $value) { if (strncmp($input_name, $cf_prefix, $len_cfp) == 0) { $dummy = explode('_', $input_name); $map_nodeid_array_cfnames[$dummy[$cf_nodeid_pos]][] = $input_name; } } if (isset($exec_data['do_bulk_save'])) { // create structure to use common algoritm $item2loop = $exec_data['status']; $is_bulk_save = 1; $bulk_notes = $db->prepare_string(trim($exec_data['bulk_exec_notes'])); $execStatusKey = 'status'; } else { $item2loop = $exec_data['save_results']; $is_bulk_save = 0; $execStatusKey = 'statusSingle'; } $addIssueOp = array('createIssue' => null, 'issueForStep' => null); foreach ($item2loop as $tcversion_id => $val) { $tcase_id = $exec_data['tc_version'][$tcversion_id]; $current_status = $exec_data[$execStatusKey][$tcversion_id]; $version_number = $exec_data['version_number'][$tcversion_id]; $has_been_executed = $current_status != $resultsCfg['status_code']['not_run'] ? TRUE : FALSE; if ($has_been_executed) { $my_notes = $is_bulk_save ? $bulk_notes : $db->prepare_string(trim($exec_data['notes'][$tcversion_id])); $sql = "INSERT INTO {$executions_table} " . "(build_id,tester_id,status,testplan_id,tcversion_id," . " execution_ts,notes,tcversion_number,platform_id,execution_duration)" . " VALUES ( {$exec_signature->build_id}, {$exec_signature->user_id}, '{$exec_data[$execStatusKey][$tcversion_id]}'," . "{$exec_signature->tplan_id}, {$tcversion_id},{$db_now},'{$my_notes}'," . "{$version_number},{$exec_signature->platform_id}"; $dura = 'NULL '; if (isset($exec_data['execution_duration'])) { if (trim($exec_data['execution_duration']) == '') { $dura = 'NULL '; } else { $dura = floatval($exec_data['execution_duration']); } } $sql .= ',' . $dura . ")"; $db->exec_query($sql); // at least for Postgres DBMS table name is needed. $execution_id = $db->insert_id($executions_table); $execSet[$tcversion_id] = $execution_id; if ($has_custom_fields) { // test useful when doing bulk update, because some type of custom fields // like checkbox can not exist on exec_data. => why ?? // $hash_cf = null; $access_key = $is_bulk_save ? 0 : $tcase_id; if (isset($map_nodeid_array_cfnames[$access_key])) { foreach ($map_nodeid_array_cfnames[$access_key] as $cf_v) { $hash_cf[$cf_v] = $exec_data[$cf_v]; } } $cfield_mgr->execution_values_to_db($hash_cf, $tcversion_id, $execution_id, $exec_signature->tplan_id, $cf_map); } $hasMoreData = new stdClass(); $hasMoreData->step_notes = isset($exec_data['step_notes']); $hasMoreData->step_status = isset($exec_data['step_status']); $hasMoreData->nike = $execCfg->steps_exec && ($hasMoreData->step_notes || $hasMoreData->step_status); if ($hasMoreData->nike) { $target = DB_TABLE_PREFIX . 'execution_tcsteps'; $key2loop = array_keys($exec_data['step_notes']); foreach ($key2loop as $step_id) { $doIt = !is_null($exec_data['step_notes'][$step_id]) && trim($exec_data['step_notes'][$step_id]) != '' || $exec_data['step_status'][$step_id] != $resultsCfg['status_code']['not_run']; if ($doIt) { $sql = " INSERT INTO {$target} (execution_id,tcstep_id,notes"; $values = " VALUES ( {$execution_id}, {$step_id}," . "'" . $db->prepare_string($exec_data['step_notes'][$step_id]) . "'"; $status = strtolower(trim($exec_data['step_status'][$step_id])); $status = $status[0]; if ($status != $resultsCfg['status_code']['not_run']) { $sql .= ",status"; $values .= ",'" . $db->prepare_string($status) . "'"; } $sql .= ") " . $values . ")"; $db->exec_query($sql); $execution_tcsteps_id = $db->insert_id($target); // NOW MANAGE attachments if (isset($_FILES['uploadedFile']['name'][$step_id]) && !is_null($_FILES['uploadedFile']['name'][$step_id])) { $repOpt = array('allow_empty_title' => TRUE); // May be we have enabled MULTIPLE on file upload if (is_array($_FILES['uploadedFile']['name'][$step_id])) { $curly = count($_FILES['uploadedFile']['name'][$step_id]); for ($moe = 0; $moe < $curly; $moe++) { $fSize = isset($_FILES['uploadedFile']['size'][$step_id][$moe]) ? $_FILES['uploadedFile']['size'][$step_id][$moe] : 0; $fTmpName = isset($_FILES['uploadedFile']['tmp_name'][$step_id][$moe]) ? $_FILES['uploadedFile']['tmp_name'][$step_id][$moe] : ''; if ($fSize && $fTmpName != "") { $fk2loop = array_keys($_FILES['uploadedFile']); foreach ($fk2loop as $tk) { $fInfo[$tk] = $_FILES['uploadedFile'][$tk][$step_id][$moe]; } $uploaded = $docRepo->insertAttachment($execution_tcsteps_id, $target, '', $fInfo, $repOpt); } } } else { $fSize = isset($_FILES['uploadedFile']['size'][$step_id]) ? $_FILES['uploadedFile']['size'][$step_id] : 0; $fTmpName = isset($_FILES['uploadedFile']['tmp_name'][$step_id]) ? $_FILES['uploadedFile']['tmp_name'][$step_id] : ''; if ($fSize && $fTmpName != "") { $fk2loop = array_keys($_FILES['uploadedFile']); foreach ($fk2loop as $tk) { $fInfo[$tk] = $_FILES['uploadedFile'][$tk][$step_id]; } $uploaded = $docRepo->insertAttachment($execution_tcsteps_id, $target, '', $fInfo); } } } } } } $itCheckOK = !is_null($issueTracker) && method_exists($issueTracker, 'addIssue'); // re-init $addIssueOp = array('createIssue' => null, 'issueForStep' => null); if ($itCheckOK) { $execContext = new stdClass(); $execContext->exec_id = $execution_id; $execContext->tcversion_id = $tcversion_id; $execContext->user = $exec_signature->user; $execContext->basehref = $exec_signature->basehref; $execContext->tplan_apikey = $exec_signature->tplan_apikey; // Issue on Test Case if (isset($exec_data['createIssue'])) { completeCreateIssue($execContext, $exec_signature); $addIssueOp['createIssue'] = addIssue($db, $execContext, $issueTracker); } // Issues at step level if (isset($exec_data['issueForStep'])) { foreach ($exec_data['issueForStep'] as $stepID => $val) { completeIssueForStep($execContext, $exec_signature, $exec_data, $stepID); $addIssueOp['issueForStep'][$stepID] = addIssue($db, $execContext, $issueTracker, $stepID); } } } // $itCheckOK } } return array($execSet, $addIssueOp); }