control.php 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  1. <?php
  2. /**
  3. * The control file of testtask module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Chunsheng Wang <chunsheng@cnezsoft.com>
  8. * @package testtask
  9. * @version $Id: control.php 5114 2013-07-12 06:02:59Z chencongzhi520@gmail.com $
  10. * @link https://www.zentao.net
  11. */
  12. class testtask extends control
  13. {
  14. /**
  15. * 产品键值对。
  16. * Product key-value pairs.
  17. *
  18. * @var array
  19. * @access public
  20. */
  21. public $products = array();
  22. /**
  23. * 项目 ID。
  24. * Project id.
  25. *
  26. * @var int
  27. * @access public
  28. */
  29. public $projectID = 0;
  30. /**
  31. * 扩展构造方法,获取产品键值对。
  32. * Extend the constructor to get product key-value pairs.
  33. *
  34. * @param string $moduleName
  35. * @param string $methodName
  36. * @access public
  37. * @return void
  38. */
  39. public function __construct($moduleName = '', $methodName = '')
  40. {
  41. parent::__construct($moduleName, $methodName);
  42. if(static::class == 'testtask')
  43. {
  44. $products = $this->testtaskZen->getProducts();
  45. /* 如果没有获取到产品键值对、并且即不是弹窗页面,并且是 zin 或者 fetch 请求,那么跳转到错误提示页面。*/
  46. /* If the product key-value pair is not obtained and it is not a pop-up page, and it is a zin request or a fetch request, then jump to the error page. */
  47. if(empty($products) && !isInModal() && (helper::isAjaxRequest('zin') || helper::isAjaxRequest('fetch')))
  48. {
  49. $tab = ($this->app->tab == 'project' || $this->app->tab == 'execution') ? $this->app->tab : 'qa';
  50. $objectID = ($tab == 'project' || $tab == 'execution') ? $this->session->$tab : 0;
  51. $this->locate($this->createLink('product', 'showErrorNone', "moduleName={$tab}&activeMenu=testtask&objectID=$objectID"));
  52. }
  53. $this->products = $products;
  54. $this->view->products = $products;
  55. }
  56. }
  57. /**
  58. * 测试单的列表。
  59. * Browse testtasks.
  60. *
  61. * @param int $productID
  62. * @param string $branch
  63. * @param string $type
  64. * @param string $orderBy
  65. * @param int $recTotal
  66. * @param int $recPerPage
  67. * @param int $pageID
  68. * @param string $beginTime
  69. * @param string $endTime
  70. * @access public
  71. * @return void
  72. */
  73. public function browse($productID = 0, $branch = '0', $type = 'local,totalStatus', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1, $beginTime = '', $endTime = '')
  74. {
  75. /* 检查是否有权限访问测试单所属产品。*/
  76. /* Check if user have permission to access the product to which the testtask belongs. */
  77. $productID = $this->loadModel('product')->checkAccess($productID, $this->products);
  78. /* 保存部分内容到 session 中供后面使用。*/
  79. /* Save session. */
  80. $uri = $this->app->getURI(true);
  81. $this->session->set('testtaskList', $uri, 'qa');
  82. $this->session->set('reportList', $uri, 'qa');
  83. $this->session->set('buildList', $uri, 'execution');
  84. /* 预处理部分变量供查询使用。*/
  85. /* Prepare variables for query. */
  86. $this->app->loadClass('pager', $static = true);
  87. $pager = pager::init($recTotal, $recPerPage, $pageID);
  88. $beginTime = $beginTime ? date('Y-m-d', strtotime($beginTime)) : '';
  89. $endTime = $endTime ? date('Y-m-d', strtotime($endTime)) : '';
  90. $sort = common::appendOrder($orderBy);
  91. $product = $this->product->getById($productID);
  92. /* 处理分支。 */
  93. /* Process branch. */
  94. $branch = $this->testtaskZen->getBrowseBranch($branch, $product->type);
  95. /* 设置1.5级菜单。 */
  96. /* Set 1.5 level menu. */
  97. $this->loadModel('qa')->setMenu($productID, $branch);
  98. /* 从数据库中查询符合条件的测试单。*/
  99. /* Query the testtasks from the database. */
  100. $testtasks = $this->testtask->getProductTasks($productID, $branch, $type, $beginTime, $endTime, $sort, $pager);
  101. /* Process testtask members. */
  102. $users = $this->loadModel('user')->getPairs('noclosed|noletter');
  103. foreach($testtasks as $testtask)
  104. {
  105. $testtask->rawStatus = $testtask->status;
  106. $testtask->status = $this->processStatus('testtask', $testtask);
  107. if(empty($testtask->members)) continue;
  108. $members = array();
  109. foreach(explode(',', $testtask->members) as $member) $members[] = zget($users, $member);
  110. $testtask->members = implode(',', array_unique($members));
  111. }
  112. $this->testtaskZen->prepareSummaryForBrowse($testtasks);
  113. $this->view->title = $product->name . $this->lang->hyphen . $this->lang->testtask->common;
  114. $this->view->users = $users;
  115. $this->view->tasks = $testtasks;
  116. $this->view->product = $product;
  117. $this->view->branch = $branch;
  118. $this->view->type = $type;
  119. $this->view->orderBy = $orderBy;
  120. $this->view->pager = $pager;
  121. $this->view->beginTime = $beginTime;
  122. $this->view->endTime = $endTime;
  123. $this->view->multipleSprints = $this->loadModel('execution')->fetchExecutionList(0, 'all', $productID);
  124. $this->display();
  125. }
  126. /**
  127. * 单元测试列表页面。
  128. * Browse unit tasks.
  129. *
  130. * @param int $productID
  131. * @param string $browseType
  132. * @param string $orderBy
  133. * @param int $recTotal
  134. * @param int $recPerPage
  135. * @param int $pageID
  136. * @access public
  137. * @return void
  138. */
  139. public function browseUnits($productID = 0, $browseType = 'newest', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
  140. {
  141. /* 检查是否有权限访问测试单所属产品。*/
  142. /* Check if user have permission to access the product to which the testtask belongs. */
  143. $productID = $this->loadModel('product')->checkAccess($productID, $this->products);
  144. /* 保存部分内容到 session 中供后面使用。*/
  145. /* Save session. */
  146. $this->session->set('testtaskList', $this->app->getURI(true), 'qa');
  147. $this->session->set('caseList', $this->app->getURI(true), $this->app->tab);
  148. $this->session->set('buildList', $this->app->getURI(true) . '#app=' . $this->app->tab, 'execution');
  149. $this->loadModel('qa')->setMenu($productID);
  150. /* 确保二级导航高亮的是测试用例。*/
  151. /* Make sure the secondary navigation highlights test cases. */
  152. $this->lang->qa->menu->testcase['subModule'] .= ',testtask';
  153. /* 预处理部分变量供查询使用。*/
  154. /* Prepare variables for query. */
  155. if($browseType == 'newest') $recPerPage = '10';
  156. $this->app->loadClass('pager', true);
  157. $pager = pager::init($recTotal, $recPerPage, $pageID);
  158. $sort = common::appendOrder($orderBy);
  159. $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->testtask->common;
  160. $this->view->tasks = $this->testtask->getProductUnitTasks($productID, $browseType, $sort, $pager);
  161. $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
  162. $this->view->product = $this->product->getByID($productID);
  163. $this->view->browseType = $browseType;
  164. $this->view->orderBy = $orderBy;
  165. $this->view->pager = $pager;
  166. $this->display();
  167. }
  168. /**
  169. * 创建测试单页面和创建表单的提交。
  170. * Create a testtask.
  171. *
  172. * @param int $productID
  173. * @param int $executionID
  174. * @param int $build
  175. * @param int $projectID
  176. * @access public
  177. * @return void
  178. */
  179. public function create($productID, $executionID = 0, $build = 0, $projectID = 0)
  180. {
  181. /* 检查是否有权限访问测试单所属产品。*/
  182. /* Check if user have permission to access the product to which the testtask belongs. */
  183. $productID = $this->loadModel('product')->checkAccess($productID, $this->products);
  184. if(!empty($_POST))
  185. {
  186. /* 生成表单数据。*/
  187. /* Generate form data. */
  188. $formData = form::data($this->config->testtask->form->create)->add('project', $projectID)->get();
  189. $formData = $this->loadModel('file')->processImgURL($formData, $this->config->testtask->editor->create['id'], $this->post->uid);
  190. if($formData->execution)
  191. {
  192. $execution = $this->loadModel('execution')->fetchByID($formData->execution);
  193. $formData->project = $execution->project;
  194. }
  195. if($formData->build && empty($formData->execution))
  196. {
  197. $build = $this->loadModel('build')->getById((int)$this->post->build);
  198. $formData->project = $build->project;
  199. }
  200. $formData->members = trim($formData->members, ',');
  201. /* 创建测试单。*/
  202. /* Create a testtask. */
  203. $testtaskID = $this->testtask->create($formData);
  204. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  205. /* 处理上传的文件。*/
  206. /* Process uploaded files. */
  207. $this->loadModel('file')->updateObjectID($this->post->uid, $testtaskID, 'testtask');
  208. $this->file->saveUpload('testtask', $testtaskID);
  209. /* 执行工作流的扩展动作并返回提示消息。*/
  210. /* Execute the extended action of the workflow and return a prompt message. */
  211. $message = $this->executeHooks($testtaskID) ?: $this->lang->saveSuccess;
  212. /* 根据不同的应用生成不同的跳转链接。*/
  213. /* Create different links according to different applications. */
  214. $testtask = $this->testtask->fetchByID($testtaskID);
  215. if($this->app->tab == 'project') $link = $this->createLink('project', 'testtask', "projectID={$testtask->project}");
  216. if($this->app->tab == 'execution') $link = $this->createLink('execution', 'testtask', "executionID={$testtask->execution}");
  217. if($this->app->tab == 'qa') $link = $this->createLink('testtask', 'browse', "productID={$this->post->product}");
  218. return $this->send(array('result' => 'success', 'message' => $message, 'load' => $link, 'id' => $testtaskID));
  219. }
  220. $this->testtaskZen->setMenu($productID, 0, $projectID, $executionID);
  221. $this->testtaskZen->assignForCreate($productID, $projectID, $executionID, $build);
  222. $this->display();
  223. }
  224. /**
  225. * 查看当前测试单的详细信息。
  226. * View detail of a testtask.
  227. *
  228. * @param int $testtaskID
  229. * @access public
  230. * @return void
  231. */
  232. public function view($testtaskID)
  233. {
  234. /* 查询测试单详细信息。 */
  235. /* Query detail of a testtask. */
  236. $testtask = $this->testtask->getByID($testtaskID, true);
  237. if(!$testtask) return $this->send(array('result' => 'fail', 'load' => array('alert' => $this->lang->notFound, 'locate' => $this->createLink('qa', 'index'))));
  238. $this->testtaskZen->setMenu($testtask->product, $testtask->branch, $testtask->project, $testtask->execution, $testtask);
  239. $this->testtaskZen->setDropMenu($testtask->product, $testtask);
  240. /* session 改变时重新查询关联的产品。*/
  241. /* When the session changes, query the related products again. */
  242. $products = $this->products;
  243. if($this->session->project != $testtask->project) $products = $this->loadModel('product')->getProductPairsByProject($testtask->project);
  244. $this->session->project = $testtask->project;
  245. /* 如果测试单所属产品在产品键值对中不存在,将其加入。*/
  246. /* Prepare the product key-value pairs. */
  247. if(!isset($products[$testtask->product]))
  248. {
  249. $product = $this->loadModel('product')->getByID($testtask->product);
  250. $products[$product->id] = $product->name;
  251. }
  252. /* 执行工作流配置的扩展动作。*/
  253. /* Execute extended actions configured in the workflow. */
  254. $this->executeHooks($testtaskID);
  255. if(!empty($testtask->execution)) $this->view->execution = $this->loadModel('project')->getByID((int)$testtask->execution);
  256. $this->view->title = "TASK #$testtask->id $testtask->name/" . $products[$testtask->product];
  257. $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
  258. $this->view->actions = $this->loadModel('action')->getList('testtask', $testtaskID);
  259. $this->view->testreport = $this->loadModel('testreport')->getById($testtask->testreport);
  260. $this->view->buildName = $testtask->build == 'trunk' ? $this->lang->trunk : $testtask->buildName;
  261. $this->view->task = $testtask;
  262. $this->view->productID = $testtask->product;
  263. $this->display();
  264. }
  265. /**
  266. * 查看单元测试测试单的用例列表。
  267. * Browse cases of a testtask which is unit test.
  268. *
  269. * @param int $testtaskID
  270. * @param string $orderBy
  271. * @param int $recTotal
  272. * @param int $recPerPage
  273. * @param int $pageID
  274. * @access public
  275. * @return void
  276. */
  277. public function unitCases($testtaskID, $orderBy = 't1.id_asc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
  278. {
  279. $testtask = $this->testtask->getByID($testtaskID);
  280. /* 检查是否有权限访问测试单所属产品。*/
  281. /* Check if user have permission to access the product to which the testtask belongs. */
  282. $productID = $this->loadModel('product')->checkAccess($testtask->product, $this->products);
  283. $this->loadModel('qa')->setMenu($productID);
  284. $this->lang->qa->menu->testcase['subModule'] .= ',testtask';
  285. /* 根据测试套件获取测试用例执行结果。*/
  286. /* Get testrun of test cases by suite. */
  287. $suiteRuns = $this->testtask->getRunsForUnitCases($testtaskID, "t4.suite_asc,$orderBy");
  288. /* 保存部分内容到 session 中供后面使用。*/
  289. /* Save session .*/
  290. $this->session->set('caseList', $this->app->getURI(true), 'qa');
  291. $this->loadModel('common')->saveQueryCondition($this->dao->get(), 'testcase', false);
  292. /* 因为套件和测试单是多对多关系,所以要过滤掉相同ID的测试单执行数据。 */
  293. /* Filter out the testrun data with the same ID because the suite and testtask have a many-to-many relationship. */
  294. $runs = array();
  295. foreach($suiteRuns as $run) $runs[$run->id] = $run;
  296. $runs = $this->loadModel('testcase')->appendData($runs, 'testrun');
  297. /* Process runs. */
  298. $this->app->loadClass('pager', $static = true);
  299. $pager = pager::init(count($runs), $recPerPage, $pageID);
  300. $runs = array_chunk($runs, $pager->recPerPage, true);
  301. $runs = empty($runs) ? $runs : (isset($runs[$pageID - 1]) ? $runs[$pageID - 1] : current($runs));
  302. $runs = $this->testtaskZen->processRowspanForUnitCases($runs);
  303. $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->testcase->common;
  304. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  305. $this->view->runs = $runs;
  306. $this->view->productID = $productID;
  307. $this->view->taskID = $testtaskID;
  308. $this->view->pager = $pager;
  309. $this->display();
  310. }
  311. /**
  312. * 查看非单元测试的测试单的用例列表。
  313. * Browse cases of a testtask which isn't unit test.
  314. *
  315. * @param int $taskID
  316. * @param string $browseType all|assignedtome|bysuite|byModule
  317. * @param string $orderBy
  318. * @param int $param
  319. * @param int $recTotal
  320. * @param int $recPerPage
  321. * @param int $pageID
  322. * @access public
  323. * @return void
  324. */
  325. public function cases($taskID, $browseType = 'all', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
  326. {
  327. /* 获取测试单信息。*/
  328. /* Get testtask info. */
  329. $testtask = $this->testtask->getByID($taskID);
  330. if(!$testtask) return $this->send(array('result' => 'fail', 'load' => array('alert' => $this->lang->testtask->checkLinked, 'locate' => array('back' => true))));
  331. if(!$this->loadModel('common')->checkPrivByObject('project', $testtask->project)) return $this->sendError($this->lang->project->accessDenied, inlink('browse'));
  332. if($testtask->execution && !$this->loadModel('common')->checkPrivByObject('execution', $testtask->execution)) return $this->sendError($this->lang->execution->accessDenied, inlink('browse'));
  333. /* 检查是否有权限访问测试单所属产品。*/
  334. /* Check if user have permission to access the product to which the testtask belongs. */
  335. $this->testtaskZen->setMenu($testtask->product, (string)$testtask->branch, $testtask->project, $testtask->execution, $testtask);
  336. $productID = $this->loadModel('product')->checkAccess($testtask->product, $this->products);
  337. /* 预处理部分变量供后面使用。*/
  338. /* Prepare variables. */
  339. $browseType = strtolower($browseType);
  340. $param = (int)$param;
  341. /* 保存部分内容到 session 中供后面使用。*/
  342. /* Save session. */
  343. $this->session->set('caseList', $this->app->getURI(true), $this->app->tab);
  344. if($browseType != 'bymodule') $this->session->set('taskCaseBrowseType', $browseType);
  345. /* 保存部分内容到 cookie 中供后面使用。*/
  346. /* Save cookies. */
  347. if($this->cookie->preTaskID != $taskID) helper::setcookie('taskCaseModule', 0, 0);
  348. helper::setcookie('preTaskID', $taskID);
  349. if($browseType == 'bymodule') helper::setcookie('taskCaseModule', $param, 0);
  350. /* 如果测试单所属产品在产品键值对中不存在,将其加入。*/
  351. /* Prepare the product key-value pairs. */
  352. $product = $this->loadModel('product')->getByID($productID);
  353. if(!isset($this->products[$productID])) $this->products[$productID] = $product->name;
  354. /* 预处理部分变量供查询使用。*/
  355. /* Prepare variables for query. */
  356. $this->app->loadClass('pager', $static = true);
  357. $pager = pager::init($recTotal, $recPerPage, $pageID);
  358. $queryID = ($browseType == 'bysearch' or $browseType == 'bysuite') ? $param : 0;
  359. $moduleID = ($browseType == 'bymodule') ? $param : ($browseType == 'bysearch' ? 0 : ((int)$this->cookie->taskCaseModule ?: 0));
  360. $sort = common::appendOrder($orderBy, 't2.id');
  361. $sort = str_replace('case_', 'id_', $sort);
  362. /* 从数据库中查询一个测试单下关联的测试用例。*/
  363. /* Query the cases associated with a testtask from the database. */
  364. $runs = $this->testtask->getTaskCases($productID, $browseType, $queryID, $moduleID, $sort, $pager, $testtask);
  365. $this->loadModel('common')->saveQueryCondition($this->dao->get(), 'testcase', false);
  366. list($runs, $scenes) = $this->testtask->getSceneCases($productID, $runs);
  367. $this->testtaskZen->setSearchParamsForCases($product, $moduleID, $testtask, $queryID);
  368. $this->testtaskZen->assignForCases($product, $testtask, $runs, $scenes, $moduleID, $browseType, $param, $orderBy, $pager);
  369. $this->display();
  370. }
  371. /**
  372. * 查看一个测试单的报表。
  373. * The report page of a testtask.
  374. *
  375. * @param int $productID
  376. * @param int $taskID
  377. * @param string $browseType
  378. * @param int $branchID
  379. * @param int $moduleID
  380. * @param string $chartType
  381. * @access public
  382. * @return void
  383. */
  384. public function report($productID, $taskID, $browseType, $branchID, $moduleID = 0, $chartType = 'pie')
  385. {
  386. $this->loadModel('report');
  387. $charts = $datas = array();
  388. if(!empty($_POST))
  389. {
  390. $this->app->loadLang('testcase');
  391. foreach($this->post->charts as $chart)
  392. {
  393. $chartFunc = 'getDataOf' . $chart;
  394. $chartData = $this->testtask->$chartFunc($taskID);
  395. $chartOption = $this->config->testtask->report->options;
  396. if(!empty($chartType))
  397. {
  398. $chartOption->type = $chartType;
  399. $chartOption->graph->caption = $this->lang->testtask->report->charts[$chart];
  400. }
  401. $charts[$chart] = $chartOption;
  402. $datas[$chart] = $this->report->computePercent($chartData);
  403. }
  404. }
  405. $task = $this->testtask->getByID($taskID);
  406. $this->testtaskZen->setMenu($task->product, $branchID, $task->project, $task->execution, $task);
  407. $this->testtaskZen->setDropMenu($task->product, $task);
  408. /* 如果测试单所属产品在产品键值对中不存在,将其加入。*/
  409. /* Prepare the product key-value pairs. */
  410. if(!isset($this->products[$task->product]))
  411. {
  412. $product = $this->loadModel('product')->getByID($task->product);
  413. $this->products[$product->id] = $product->name;
  414. }
  415. $this->view->title = $this->products[$task->product] . $this->lang->hyphen . $this->lang->testtask->common . $this->lang->hyphen . $this->lang->testtask->reportChart;
  416. $this->view->productID = $task->product;
  417. $this->view->taskID = $taskID;
  418. $this->view->browseType = $browseType;
  419. $this->view->moduleID = $moduleID;
  420. $this->view->branchID = $branchID;
  421. $this->view->chartType = $chartType;
  422. $this->view->charts = $charts;
  423. $this->view->datas = $datas;
  424. $this->display();
  425. }
  426. /**
  427. * 分组浏览一个测试单关联的用例。
  428. * Browse the cases associated with a testtask in groups.
  429. *
  430. * @param int $taskID
  431. * @param string $browseType
  432. * @access public
  433. * @return void
  434. */
  435. public function groupCase($taskID, $browseType = 'all')
  436. {
  437. /* 检查测试单是否存在。*/
  438. /* Check if the testtask exists. */
  439. $task = $this->testtask->getByID($taskID);
  440. if(!$task) return $this->send(array('result' => 'fail', 'load' => array('alert' => $this->lang->notFound, 'locate' => $this->createLink('qa', 'index'))));
  441. /* 检查是否有权限访问测试单所属产品。*/
  442. /* Check if user have permission to access the product to which the testtask belongs. */
  443. $this->testtaskZen->setMenu($task->product, $task->branch, $task->project, $task->execution, $task);
  444. $this->testtaskZen->setDropMenu($task->product, $task);
  445. $productID = $this->loadModel('product')->checkAccess($task->product, $this->products);
  446. /* 保存部分内容到 session 和 cookie 中供后面使用。*/
  447. /* Save session and cookie. */
  448. $this->session->set('caseList', $this->app->getURI(true), 'qa');
  449. helper::setcookie('taskCaseModule', 0, 0);
  450. /* 如果测试单所属产品在产品键值对中不存在,将其加入。*/
  451. /* Prepare the product key-value pairs. */
  452. if(!isset($this->products[$productID]))
  453. {
  454. $product = $this->loadModel('product')->getByID($productID);
  455. $this->products[$productID] = $product->name;
  456. }
  457. /* 从数据库中查询一个测试单下关联的测试用例。*/
  458. /* Query the cases associated with a testtask from the database. */
  459. if(!isset($this->lang->testtask->featureBar['groupcase'][$browseType])) $browseType = 'all';
  460. $cases = $this->testtask->getTaskCases($productID, $browseType, 0, 0, 'story', null, $task);
  461. $this->loadModel('common')->saveQueryCondition($this->dao->get(), 'testcase', false);
  462. $cases = $this->loadModel('testcase')->appendData($cases, 'run');
  463. /* 处理测试用例的跨行合并属性供前端组件分组使用。*/
  464. /* Process the rowspan property of cases for use by front-end component groupings. */
  465. $cases = $this->testtaskZen->processRowspanForGroupCase($cases, $task->build);
  466. $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->testtask->cases;
  467. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  468. $this->view->canBeChanged = common::canBeChanged('testtask', $task);
  469. $this->view->productID = $productID;
  470. $this->view->cases = $cases;
  471. $this->view->task = $task;
  472. $this->view->browseType = $browseType;
  473. $this->display();
  474. }
  475. /**
  476. * 编辑一个测试单。
  477. * Edit a testtask.
  478. *
  479. * @param int $taskID
  480. * @access public
  481. * @return void
  482. */
  483. public function edit($taskID)
  484. {
  485. if(!empty($_POST))
  486. {
  487. $oldTask = $this->testtask->getByID($taskID);
  488. $task = $this->testtaskZen->buildTaskForEdit($taskID, $oldTask->product);
  489. $this->testtaskZen->checkTaskForEdit($task);
  490. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  491. $changes = $this->testtask->update($task, $oldTask);
  492. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  493. if($changes || $this->post->comment)
  494. {
  495. $actionID = $this->loadModel('action')->create('testtask', $taskID, 'edited', $this->post->comment);
  496. $this->action->logHistory($actionID, $changes);
  497. }
  498. $message = $this->executeHooks($taskID) ?: $this->lang->saveSuccess;
  499. if(isInModal()) return $this->send(array('result' => 'success', 'message' => $message, 'load' => true));
  500. return $this->send(array('result' => 'success', 'message' => $message, 'load' => $this->session->testtaskList, 'closeModal' => true));
  501. }
  502. /* Get task info. */
  503. $task = $this->testtask->getByID($taskID);
  504. $this->testtaskZen->setMenu($task->product, $task->branch, $task->project, $task->execution, $task);
  505. $productID = $this->loadModel('product')->checkAccess($task->product, $this->products);
  506. /* 如果测试单所属产品在产品键值对中不存在,将其加入。*/
  507. /* Prepare the product key-value pairs. */
  508. if(!isset($this->products[$productID]))
  509. {
  510. $product = $this->product->getByID($productID);
  511. $this->products[$product->id] = $product->name;
  512. }
  513. $this->testtaskZen->assignForEdit($task, $productID);
  514. $this->display();
  515. }
  516. /**
  517. * 开始一个测试单。
  518. * Start a testtask.
  519. *
  520. * @param int $taskID
  521. * @access public
  522. * @return void
  523. */
  524. public function start($taskID)
  525. {
  526. if(!empty($_POST))
  527. {
  528. $task = $this->testtaskZen->buildTaskForStart($taskID);
  529. $changes = $this->testtask->start($task);
  530. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  531. if($changes || $this->post->comment)
  532. {
  533. $actionID = $this->loadModel('action')->create('testtask', $taskID, 'Started', $this->post->comment);
  534. $this->action->logHistory($actionID, $changes);
  535. }
  536. $message = $this->executeHooks($taskID) ?: $this->lang->saveSuccess;
  537. return $this->send(array('result' => 'success', 'message' => $message, 'closeModal' => true, 'load' => true));
  538. }
  539. /* Set menu. */
  540. $testtask = $this->testtask->getByID($taskID);
  541. $this->testtaskZen->setMenu($testtask->product, $testtask->branch, $testtask->project, $testtask->execution, $testtask);
  542. $this->loadModel('product')->checkAccess($testtask->product, $this->products);
  543. $this->view->title = $testtask->name . $this->lang->hyphen . $this->lang->testtask->start;
  544. $this->view->actions = $this->loadModel('action')->getList('testtask', $taskID);
  545. $this->view->users = $this->loadModel('user')->getPairs('nodeleted', $testtask->owner);
  546. $this->view->testtask = $testtask;
  547. $this->display();
  548. }
  549. /**
  550. * 关闭一个测试单。
  551. * Close a testtask.
  552. *
  553. * @param int $taskID
  554. * @access public
  555. * @return void
  556. */
  557. public function close($taskID)
  558. {
  559. if(!empty($_POST))
  560. {
  561. $task = $this->testtaskZen->buildTaskForClose($taskID);
  562. $changes = $this->testtask->close($task);
  563. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  564. if($changes || $this->post->comment)
  565. {
  566. $actionID = $this->loadModel('action')->create('testtask', $taskID, 'Closed', $this->post->comment);
  567. if($changes) $this->action->logHistory($actionID, $changes);
  568. }
  569. $message = $this->executeHooks($taskID) ?: $this->lang->saveSuccess;
  570. return $this->send(array('result' => 'success', 'message' => $message, 'closeModal' => true, 'load' => true));
  571. }
  572. /* Set menu. */
  573. $testtask = $this->testtask->getByID($taskID);
  574. $this->testtaskZen->setMenu($testtask->product, $testtask->branch, $testtask->project, $testtask->execution, $testtask);
  575. $this->loadModel('product')->checkAccess($testtask->product, $this->products);
  576. $this->view->title = $testtask->name . $this->lang->hyphen . $this->lang->close;
  577. $this->view->actions = $this->loadModel('action')->getList('testtask', $taskID);
  578. $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted|qdfirst');
  579. $this->view->testtask = $testtask;
  580. $this->display();
  581. }
  582. /**
  583. * 阻塞一个测试单。
  584. * Block a testtask.
  585. *
  586. * @param int $taskID
  587. * @access public
  588. * @return void
  589. */
  590. public function block($taskID)
  591. {
  592. if(!empty($_POST))
  593. {
  594. $task = $this->testtaskZen->buildTaskForBlock($taskID);
  595. $changes = $this->testtask->block($task);
  596. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  597. if($changes || $this->post->comment)
  598. {
  599. $actionID = $this->loadModel('action')->create('testtask', $taskID, 'Blocked', $this->post->comment);
  600. $this->action->logHistory($actionID, $changes);
  601. }
  602. $message = $this->executeHooks($taskID) ?: $this->lang->saveSuccess;
  603. return $this->send(array('result' => 'success', 'message' => $message, 'closeModal' => true, 'load' => true));
  604. }
  605. /* Set menu. */
  606. $testtask = $this->testtask->getByID($taskID);
  607. $this->testtaskZen->setMenu($testtask->product, $testtask->branch, $testtask->project, $testtask->execution, $testtask);
  608. $this->loadModel('product')->checkAccess($testtask->product, $this->products);
  609. $this->view->title = $testtask->name . $this->lang->hyphen . $this->lang->testtask->block;
  610. $this->view->actions = $this->loadModel('action')->getList('testtask', $taskID);
  611. $this->view->users = $this->loadModel('user')->getPairs('nodeleted', $testtask->owner);
  612. $this->view->testtask = $testtask;
  613. $this->display();
  614. }
  615. /**
  616. * 激活一个测试单。
  617. * Activate a testtask.
  618. *
  619. * @param int $taskID
  620. * @access public
  621. * @return void
  622. */
  623. public function activate($taskID)
  624. {
  625. if(!empty($_POST))
  626. {
  627. $task = $this->testtaskZen->buildTaskForActivate($taskID);
  628. $changes = $this->testtask->activate($task);
  629. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  630. if($changes || $this->post->comment)
  631. {
  632. $actionID = $this->loadModel('action')->create('testtask', $taskID, 'Activated', $this->post->comment);
  633. $this->action->logHistory($actionID, $changes);
  634. }
  635. $message = $this->executeHooks($taskID) ?: $this->lang->saveSuccess;
  636. return $this->send(array('result' => 'success', 'message' => $message, 'closeModal' => true, 'load' => true));
  637. }
  638. /* Set menu. */
  639. $testtask = $this->testtask->getByID($taskID);
  640. $this->testtaskZen->setMenu($testtask->product, $testtask->branch, $testtask->project, $testtask->execution, $testtask);
  641. $this->loadModel('product')->checkAccess($testtask->product, $this->products);
  642. $this->view->title = $testtask->name . $this->lang->hyphen . $this->lang->testtask->activate;
  643. $this->view->actions = $this->loadModel('action')->getList('testtask', $taskID);
  644. $this->view->users = $this->loadModel('user')->getPairs('nodeleted', $testtask->owner);
  645. $this->view->testtask = $testtask;
  646. $this->display();
  647. }
  648. /**
  649. * 删除一个测试单。
  650. * Delete a testtask.
  651. *
  652. * @param int $taskID
  653. * @access public
  654. * @return void
  655. */
  656. public function delete($taskID)
  657. {
  658. $task = $this->testtask->getByID($taskID);
  659. if(!$task) return $this->send(array('result' => 'fail', 'load' => array('alert' => $this->lang->notFound, 'locate' => $this->createLink('qa', 'index'))));
  660. $this->testtask->delete(TABLE_TESTTASK, $taskID);
  661. if(dao::isError()) return $this->send(array('result' => 'success', 'message' => dao::getError()));
  662. $message = $this->executeHooks($taskID) ?: $this->lang->saveSuccess;
  663. if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
  664. $browseList = inlink('browse', "productID=$task->product");
  665. if($this->app->tab == 'execution') $browseList = $this->createLink('execution', 'testtask', "executionID=$task->execution");
  666. if($this->app->tab == 'project') $browseList = $this->createLink('project', 'testtask', "projectID=$task->project");
  667. return $this->send(array('result' => 'success', 'message' => $message, 'load' => $this->app->methodName == 'view' ? $browseList : true, 'closeModal' => true));
  668. }
  669. /**
  670. * 关联测试用例到一个测试单。
  671. * Link cases to a testtask.
  672. *
  673. * @param int $taskID
  674. * @param string $type
  675. * @param int $param
  676. * @param int $recTotal
  677. * @param int $recPerPage
  678. * @param int $pageID
  679. * @access public
  680. * @return void
  681. */
  682. public function linkCase($taskID, $type = 'all', $param = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
  683. {
  684. if(!empty($_POST))
  685. {
  686. $runs = form::batchData($this->config->testtask->form->linkCase)->get();
  687. $this->testtask->linkCase($taskID, $type, $runs);
  688. if(dao::isError()) return $this->send(array('result' => 'success', 'message' => dao::getError()));
  689. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => inlink('cases', "taskID={$taskID}")));
  690. }
  691. /* Get testtask info. */
  692. $task = $this->testtask->getByID($taskID);
  693. if(!$task) return $this->send(array('result' => 'fail', 'load' => array('alert' => $this->lang->testtask->checkLinked, 'locate' => array('back' => true))));
  694. /* Check if user have permission to access the product to which the testtask belongs. */
  695. $this->testtaskZen->setMenu($task->product, $task->branch, $task->project, $task->execution, $task);
  696. $this->testtaskZen->setDropMenu($task->product, $task);
  697. $productID = $this->loadModel('product')->checkAccess($task->product, $this->products);
  698. /* Prepare the product key-value pairs. */
  699. $product = $this->product->getByID($productID);
  700. if(!isset($this->products[$productID])) $this->products[$productID] = $product->name;
  701. /* Save session. */
  702. $this->session->set('caseList', $this->app->getURI(true), 'qa');
  703. $this->testtaskZen->setSearchParamsForLinkCase($product, $task, $type, $param);
  704. /* 从数据库中查询一个测试单下可以关联的测试用例。*/
  705. /* Query the cases that can be associated with a testtask from the database. */
  706. $this->app->loadClass('pager', true);
  707. $pager = pager::init($recTotal, $recPerPage, $pageID);
  708. $cases = $this->testtask->getLinkableCases($productID, $task, $type, $param, $pager);
  709. $this->view->title = $task->name . $this->lang->hyphen . $this->lang->testtask->linkCase;
  710. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  711. $this->view->suites = $this->loadModel('testsuite')->getSuites($task->product);
  712. $this->view->relatedTasks = $this->testtask->getRelatedTestTasks($productID, $taskID);
  713. $this->view->cases = $cases;
  714. $this->view->task = $task;
  715. $this->view->type = $type;
  716. $this->view->param = $param;
  717. $this->view->pager = $pager;
  718. $this->view->product = $product;
  719. $this->view->branch = $task->branch;
  720. $this->display();
  721. }
  722. /**
  723. * 从测试单中移除一个用例。
  724. * Remove a case from testtask.
  725. *
  726. * @param int $runID
  727. * @access public
  728. * @return void
  729. */
  730. public function unlinkCase($runID)
  731. {
  732. $this->testtask->unlinkCase($runID);
  733. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  734. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true));
  735. }
  736. /**
  737. * 批量从测试单中移除用例。
  738. * Batch remove cases from a testtask.
  739. *
  740. * @param int $taskID
  741. * @access public
  742. * @return void
  743. */
  744. public function batchUnlinkCases($taskID)
  745. {
  746. $this->testtask->batchUnlinkCases($taskID, $this->post->caseIdList);
  747. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  748. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true));
  749. }
  750. /**
  751. * 执行一个用例。
  752. * Run a case.
  753. *
  754. * @param int $runID
  755. * @param int $caseID
  756. * @param int $version
  757. * @param string $confirm
  758. * @access public
  759. * @return void
  760. */
  761. public function runCase($runID, $caseID = 0, $version = 0, $confirm = '')
  762. {
  763. if($runID)
  764. {
  765. $run = $this->testtask->getRunById($runID);
  766. }
  767. else
  768. {
  769. $run = new stdclass();
  770. $run->case = $this->loadModel('testcase')->getById($caseID, $version);
  771. }
  772. $caseID = $caseID ?: $run->case->id;
  773. $this->testtaskZen->checkAndExecuteAutomatedTest($run, $runID, $caseID, $version, $confirm);
  774. $preAndNext = $this->loadModel('common')->getPreAndNextObject('testcase', $caseID);
  775. if(!empty($_POST))
  776. {
  777. $stepResults = form::batchData($this->config->testtask->form->runCase)->get();
  778. $deployID = (int)$this->post->deploy;// code for biz.
  779. $caseResult = $this->testtask->createResult($runID, (int)$this->post->case, (int)$this->post->version, $stepResults, $deployID);
  780. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  781. $this->loadModel('action')->create('case', $caseID, 'run', '', zget($run, 'task', '0') . ',' . $caseResult);
  782. $this->testtaskZen->responseAfterRunCase($caseResult, $preAndNext, $run, $caseID, $version);
  783. return $this->send(array('result' => 'success', 'load' => true, 'closeModal' => true));
  784. }
  785. $this->testtaskZen->assignForRunCase($run, $preAndNext, $runID, $caseID, $version, $confirm);
  786. $this->display();
  787. }
  788. /**
  789. * 批量执行用例。
  790. * Batch run cases.
  791. *
  792. * @param int $productID
  793. * @param string $orderBy
  794. * @param string $from
  795. * @param int $taskID
  796. * @param string $confirm
  797. * @access public
  798. * @return void
  799. */
  800. public function batchRun($productID, $orderBy = 'id_desc', $from = 'testcase', $taskID = 0, $confirm = '')
  801. {
  802. $url = $this->session->caseList ?: inlink('browse', "productID=$productID");
  803. if($this->post->results)
  804. {
  805. $cases = form::batchData($this->config->testtask->form->batchRun)->get();
  806. $this->testtask->batchRun($cases, $from, $taskID);
  807. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  808. if(!empty($taskID)) $this->testtask->updateStatus((int)$taskID);
  809. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $url));
  810. }
  811. /* 根据不同情况获取要批量执行的用例。*/
  812. /* Get cases to run according to different situations. */
  813. $caseIdList = $this->loadModel('testcase')->ignoreAutoCaseIdList((array)$this->post->caseIdList);
  814. if(empty($caseIdList)) $this->locate($url);
  815. $cases = $this->testtaskZen->prepareCasesForBatchRun($productID, $orderBy, $from, $taskID, $confirm, $caseIdList);
  816. if(empty($cases)) return $this->send(array('result' => 'fail', 'load' => array('alert' => $this->lang->testtask->skipChangedCases, 'locate' => $url)));
  817. $steps = $this->testcase->getStepGroupByIdList($caseIdList);
  818. $emptyCases = '';
  819. foreach($cases as $caseID => $case)
  820. {
  821. if(empty($steps[$case->id]))
  822. {
  823. unset($cases[$caseID]);
  824. $emptyCases .= empty($emptyCases) ? "{$case->id}" : ",{$case->id}";
  825. }
  826. }
  827. if(empty($cases)) return $this->send(array('result' => 'fail', 'load' => array('alert' => $this->lang->testtask->caseEmpty, 'locate' => $url)));
  828. /* 获取用例所属模块的键值对。*/
  829. /* Get key-value pairs of case module. */
  830. $this->loadModel('tree');
  831. $modules = array('/');
  832. foreach($cases as $case) $modules += $this->tree->getModulesName((array)$case->module);
  833. $this->view->title = $this->lang->testtask->batchRun;
  834. $this->view->steps = $this->loadModel('testcase')->getStepGroupByIdList($caseIdList);
  835. $this->view->modules = $modules;
  836. $this->view->cases = $cases;
  837. $this->view->caseIdList = $caseIdList;
  838. $this->view->productID = $productID;
  839. $this->view->from = $from;
  840. $this->view->emptyCases = $emptyCases;
  841. $this->display();
  842. }
  843. /**
  844. * 查看测试用例的执行结果。
  845. * View test results of a test run.
  846. *
  847. * @param int $runID
  848. * @param int $caseID
  849. * @param int $version
  850. * @param string $status all|done
  851. * @param string $type all|fail
  852. * @param int $deployID
  853. * @access public
  854. * @return void
  855. */
  856. public function results($runID, $caseID = 0, $version = 0, $status = 'done', $type = 'all', $deployID = 0)
  857. {
  858. /* Set project menu. */
  859. if($this->app->tab == 'project') $this->loadModel('project')->setMenu($this->session->project);
  860. /* Set case and results. */
  861. if($runID)
  862. {
  863. $this->app->loadLang('testcase');
  864. /* If runID is not empty, set testtask. */
  865. $run = $this->testtask->getRunById($runID);
  866. $case = $run->case;
  867. $results = $this->testtask->getResults($runID, 0, $status, $type);
  868. $this->view->testtask = $this->testtask->getByID($run->task);
  869. }
  870. else
  871. {
  872. $case = $this->loadModel('testcase')->getByID($caseID, $version);
  873. $results = $this->testtask->getResults(0, $caseID, $status, $type, $deployID);
  874. }
  875. /* Assign. */
  876. $this->view->case = $case;
  877. $this->view->runID = $runID;
  878. $this->view->results = $results;
  879. $this->view->type = $type;
  880. $this->view->builds = $this->loadModel('build')->getBuildPairs(array($case->product), $case->branch);
  881. $this->view->users = $this->loadModel('user')->getPairs('noclosed, noletter');
  882. $this->view->testtasks = $this->testtask->getPairs($case->product, 0, 0, false);
  883. $this->display();
  884. }
  885. /**
  886. * 指派测试用例。
  887. * Assign a testcase.
  888. *
  889. * @param int $runID
  890. * @access public
  891. * @return void
  892. */
  893. public function assignCase($runID)
  894. {
  895. $run = $this->testtask->getRunById($runID);
  896. if(!empty($_POST))
  897. {
  898. $newRun = form::data($this->config->testtask->form->assignCase)
  899. ->add('id', $runID)
  900. ->stripTags($this->config->testtask->editor->assignCase['id'], $this->config->allowedTags)
  901. ->get();
  902. $newRun = $this->loadModel('file')->processImgURL($newRun, $this->config->testtask->editor->assignCase['id'], $newRun->uid);
  903. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  904. $changes = $this->testtask->assignCase($newRun, $run);
  905. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  906. if(empty($changes)) return $this->sendSuccess(array('closeModal' => true, 'load' => true));
  907. $actionID = $this->loadModel('action')->create('case', (int)$run->case->id, 'assigned', '', $newRun->assignedTo);
  908. $this->action->logHistory($actionID, $changes);
  909. $message = $this->executeHooks($run->task) ?: $this->lang->saveSuccess;
  910. return $this->sendSuccess(array('message' => $message, 'closeModal' => true, 'load' => true));
  911. }
  912. /* Assign. */
  913. $this->view->users = $this->loadModel('user')->getPairs('noclosed, noletter');
  914. $this->view->run = $run;
  915. $this->display();
  916. }
  917. /**
  918. * 批量指派测试单中的用例。
  919. * Batch assign cases in a testtask.
  920. *
  921. * @param int $taskID
  922. * @param string $account
  923. * @access public
  924. * @return void
  925. */
  926. public function batchAssign($taskID, $account = '')
  927. {
  928. if(empty($account)) $account = $this->post->assignedTo;
  929. $this->testtask->batchAssign($taskID, $account, $this->post->caseIdList);
  930. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  931. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true));
  932. }
  933. /**
  934. * 导入单元测试结果。
  935. * Import unit results.
  936. *
  937. * @param int $productID
  938. * @access public
  939. * @return void
  940. */
  941. public function importUnitResult($productID)
  942. {
  943. /* 检查是否有权限访问要导入单元测试结果的产品。*/
  944. /* Check if user have permission to access the product into which unit test results are to be imported. */
  945. $productID = $this->loadModel('product')->checkAccess($productID, $this->products);
  946. if($_POST)
  947. {
  948. $this->loadModel('file');
  949. if(!is_writable($this->file->savePath)) return $this->send(array('result' => 'fail', 'message' => sprintf(strip_tags($this->lang->file->errorCanNotWrite), $this->file->savePath, $this->file->savePath)));
  950. $task = $this->testtaskZen->buildTaskForImportUnitResult($productID);
  951. $taskID = $this->testtask->importUnitResult($task);
  952. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  953. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => inlink('unitCases', "taskID=$taskID")));
  954. }
  955. $this->app->loadLang('job');
  956. $this->loadModel('qa')->setMenu($productID);
  957. /* 确保二级导航高亮的是测试用例。*/
  958. /* Make sure the secondary navigation highlights test cases. */
  959. $this->lang->qa->menu->testcase['subModule'] .= ',testtask';
  960. $executions = empty($productID) ? array() : $this->product->getExecutionPairsByProduct($productID, '', 0, '', array('review', 'design', 'request'));
  961. $builds = empty($productID) ? array() : $this->loadModel('build')->getBuildPairs(array($productID), 'all', 'notrunk', 0, 'execution', '', false);
  962. $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->testtask->importUnitResult;
  963. $this->view->users = $this->loadModel('user')->getPairs('noletter|nodeleted|noclosed');
  964. $this->view->executions = $executions;
  965. $this->view->builds = $builds;
  966. $this->view->productID = $productID;
  967. $this->display();
  968. }
  969. /**
  970. * 获取用户负责的测试单的键值对。在创建或编辑测试单类型的待办时使用。
  971. * Get the key-value pair of the testtask that the user is responsible for. Used when creating or editing a testtask type backlog.
  972. *
  973. * @param int $userID
  974. * @param string $id
  975. * @param string $status
  976. * @access public
  977. * @return void
  978. */
  979. public function ajaxGetUserTestTasks($userID = 0, $id = '', $status = 'all')
  980. {
  981. $account = $this->app->user->account;
  982. if($userID)
  983. {
  984. $user = $this->loadModel('user')->getById($userID, 'id');
  985. $account = $user->account;
  986. }
  987. $testTasks = $this->testtask->getUserTestTaskPairs($account, 0, $status);
  988. $items = array();
  989. foreach($testTasks as $taskID => $taskName) $items[] = array('text' => $taskName, 'value' => $taskID);
  990. $fieldName = $id ? "testtasks[$id]" : 'testtask';
  991. return print(json_encode(array('name' => $fieldName, 'items' => $items)));
  992. }
  993. /**
  994. * 获取一个产品下的测试单的键值对。
  995. * Get testtask key-value pairs of a product by ajax.
  996. *
  997. * @param int $productID
  998. * @param int $executionID
  999. * @param int $appendTaskID
  1000. * @access public
  1001. * @return void
  1002. */
  1003. public function ajaxGetTestTasks($productID, $executionID = 0, $appendTaskID = 0)
  1004. {
  1005. $tasks = array();
  1006. $pairs = $this->testtask->getPairs($productID, $executionID, $appendTaskID);
  1007. foreach($pairs as $taskID => $taskName) $tasks[] = array('text' => $taskName, 'value' => $taskID, 'keys' => $taskName);
  1008. return $this->send(array('result' => 'success', 'tasks' => $tasks));
  1009. }
  1010. /**
  1011. * 获取一个产品下的测试报告键值对。
  1012. * Get test report key-value pairs of a product by ajax.
  1013. *
  1014. * @param int $productID
  1015. * @access public
  1016. * @return void
  1017. */
  1018. public function ajaxGetTestReports($productID)
  1019. {
  1020. $reports = array();
  1021. $pairs = $this->loadModel('testreport')->getPairs($productID);
  1022. foreach($pairs as $id => $title) $reports[] = array('text' => $title, 'value' => $id);
  1023. return $this->send(array('result' => 'success', 'reports' => $reports));
  1024. }
  1025. /**
  1026. * 获取一个产品下的测试单的下拉列表。
  1027. * Get drop menu of testtasks of a product by ajax.
  1028. *
  1029. * // TODO: 暂时不做大的调整,重构 1.5 级导航时可能需要此方法提供数据。
  1030. *
  1031. * @param int $productID
  1032. * @param string $branch
  1033. * @param int $taskID
  1034. * @param string $module
  1035. * @param string $method
  1036. * @param string $objectType
  1037. * @param int $objectID
  1038. * @access public
  1039. * @return void
  1040. */
  1041. public function ajaxGetDropMenu($productID, $branch, $taskID, $module, $method, $objectType = '', $objectID = 0)
  1042. {
  1043. if($objectType && ($objectType == 'project' || $objectType == 'execution') && $objectID)
  1044. {
  1045. $testtasks = $objectType == 'project' ? $this->testtask->getProjectTasks($objectID, 0, 'id_desc', null) : $this->testtask->getExecutionTasks($objectID, 0, 'execution', 'id_desc', null);
  1046. }
  1047. else
  1048. {
  1049. $scope = empty($objectType) ? 'local' : 'all';
  1050. $testtasks = $this->testtask->getProductTasks($productID, $branch, "$scope,totalStatus", '', '', 'id_desc', null);
  1051. }
  1052. $namePairs = array();
  1053. foreach($testtasks as $testtaskID => $testtask) $namePairs[$testtaskID] = $testtask->name;
  1054. $params = $method == 'report' ? "productID={$productID}&taskID=%s&browseType=all&branch={$branch}" : "taskID=%s";
  1055. $this->view->currentTaskID = $taskID;
  1056. $this->view->testtasks = $testtasks;
  1057. $this->view->module = $module;
  1058. $this->view->method = $method;
  1059. $this->view->productID = $productID;
  1060. $this->view->branch = $branch;
  1061. $this->view->objectType = $objectType;
  1062. $this->view->objectID = $objectID;
  1063. $this->view->testtasksPinyin = common::convert2Pinyin($namePairs);
  1064. $this->view->link = $this->createLink($module, $method, $params);
  1065. $this->display();
  1066. }
  1067. /**
  1068. * 根据 id 获取用例的一次运行结果。
  1069. * Get a run result of a case by ajax.
  1070. *
  1071. * @param int $resultID
  1072. * @access public
  1073. * @return void
  1074. */
  1075. public function ajaxGetResult($resultID)
  1076. {
  1077. $result = $this->dao->select('*')->from(TABLE_TESTRESULT)->where('id')->eq($resultID)->fetch();
  1078. return $this->send(array('result' => 'success', 'data' => $result));
  1079. }
  1080. /**
  1081.  * AJAX: Get executionID by buildID.
  1082. *
  1083. * @param int $buildID
  1084. * @access public
  1085. * @return int
  1086. */
  1087. public function ajaxGetExecutionByBuild($buildID)
  1088. {
  1089. $execution = $this->loadModel('execution')->getByBuild($buildID);
  1090. return print($execution ? $execution->id : 0);
  1091. }
  1092. }