zen.php 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. <?php
  2. class testtaskZen extends testtask
  3. {
  4. /**
  5. * 根据不同情况设置菜单。
  6. * Set menu according to different situations.
  7. *
  8. * @param int $productID
  9. * @param int|string $branch
  10. * @param int $projectID
  11. * @param int $executionID
  12. * @param object $testtask
  13. * @access public
  14. * @return void
  15. */
  16. public function setMenu($productID, $branch, $projectID, $executionID, $testtask = null)
  17. {
  18. if($this->app->tab == 'project')
  19. {
  20. $this->view->projectID = $this->loadModel('project')->setMenu($projectID);
  21. return $this->view->projectID;
  22. }
  23. if($this->app->tab == 'execution')
  24. {
  25. $this->loadModel('execution')->setMenu($executionID);
  26. return $executionID;
  27. }
  28. return $this->loadModel('qa')->setMenu($productID, $branch);
  29. }
  30. /**
  31. * 获取列表页面的 branch 参数。
  32. * Get browse branch param.
  33. *
  34. * @param string $branch
  35. * @param string $productType
  36. * @access protected
  37. * @return string
  38. */
  39. protected function getBrowseBranch($branch, $productType)
  40. {
  41. if($productType == 'normal') return 'all';
  42. if($this->cookie->preBranch !== '' && $branch === '') $branch = (string)$this->cookie->preBranch;
  43. /* 如果是多分支产品时,设置分支的 cookie。*/
  44. /* Set branch cookie if product is multi-branch. */
  45. helper::setcookie('preBranch', $branch);
  46. $this->session->set('branch', $branch, 'qa');
  47. return $branch;
  48. }
  49. /**
  50. * 设置测试单用例列表页面搜索表单的参数。
  51. * Set congiruration of search form in cases page of testtask.
  52. *
  53. * @param object $product
  54. * @param int $moduleID
  55. * @param object $testtask
  56. * @param int $queryID
  57. * @access protected
  58. * @return void
  59. */
  60. protected function setSearchParamsForCases($product, $moduleID, $testtask, $queryID)
  61. {
  62. $this->loadModel('testcase');
  63. $searchConfig = $this->config->testcase->search;
  64. $searchConfig['module'] = 'testtask';
  65. $searchConfig['queryID'] = $queryID;
  66. $searchConfig['actionURL'] = helper::createLink('testtask', 'cases', "taskID=$testtask->id&browseType=bySearch&queryID=myQueryID");
  67. $searchConfig['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($product->id, 'case');
  68. $searchConfig['params']['lib']['values'] = $this->loadModel('caselib')->getLibraries();
  69. $searchConfig['params']['scene']['values'] = $this->testcase->getSceneMenu($product->id, $moduleID);
  70. $searchConfig['params']['status']['values'] = $this->lang->testcase->statusList;
  71. $searchConfig['params']['product']['values'] = array($product->id => $product->name, 'all' => $this->lang->testcase->allProduct);
  72. if($this->app->tab == 'project')
  73. {
  74. $searchConfig['params']['story']['values'] = $this->loadModel('story')->getExecutionStoryPairs($testtask->project, $product->id, 'all', 0, 'full', 'active');
  75. }
  76. elseif($this->app->tab == 'execution')
  77. {
  78. $searchConfig['params']['story']['values'] = $this->loadModel('story')->getExecutionStoryPairs($testtask->execution, $product->id, 'all', 0, 'full', 'active');
  79. }
  80. else
  81. {
  82. $searchConfig['params']['story']['values'] = $this->loadModel('story')->getProductStoryPairs($product->id, 'all', array(), 'active,reviewing', 'id_desc', 0, '', 'story', false);
  83. }
  84. $searchConfig['fields']['assignedTo'] = $this->lang->testtask->assignedTo;
  85. $searchConfig['params']['assignedTo'] = array('operator' => '=', 'control' => 'select', 'values' => 'users');
  86. if(!$this->config->testcase->needReview) unset($searchConfig['params']['status']['values']['wait']);
  87. if($product->shadow) unset($searchConfig['fields']['product']);
  88. if($product->type == 'normal')
  89. {
  90. unset($searchConfig['fields']['branch']);
  91. unset($searchConfig['params']['branch']);
  92. }
  93. else
  94. {
  95. $searchConfig['fields']['branch'] = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
  96. $searchConfig['params']['branch']['values'] = $this->testtask->getBranchesByTask($testtask);
  97. }
  98. $this->config->testcase->search = $searchConfig;
  99. $this->loadModel('search')->setSearchParams($searchConfig);
  100. }
  101. /**
  102. * 设置测试单关联用例页面搜索表单的参数。
  103. * Set congiruration of search form in linkCase page of testtask.
  104. *
  105. * @param object $product
  106. * @param object $task
  107. * @param string $type
  108. * @param int $param
  109. * @access protected
  110. * @return void
  111. */
  112. protected function setSearchParamsForLinkCase($product, $task, $type, $param)
  113. {
  114. $this->loadModel('testcase');
  115. $searchConfig = $this->config->testcase->search;
  116. $searchConfig['style'] = 'simple';
  117. $searchConfig['actionURL'] = inlink('linkcase', "taskID={$task->id}&type={$type}&param={$param}");
  118. $searchConfig['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($product->id, 'case', 0, $task->branch);
  119. $searchConfig['params']['scene']['values'] = $this->testcase->getSceneMenu($product->id);
  120. $searchConfig['params']['lib']['values'] = $this->loadModel('caselib')->getLibraries();
  121. if(empty($searchConfig['params']['product'])) $searchConfig['params']['product']['values'] = array($product->id => $product->name);
  122. $build = $this->loadModel('build')->getByID((int)$task->build);
  123. if($build)
  124. {
  125. $searchConfig['params']['story']['values'] = $this->dao->select('id,title')->from(TABLE_STORY)->where('id')->in($build->stories)->fetchPairs();
  126. $this->loadModel('common')->saveQueryCondition($this->dao->get(), 'story');
  127. }
  128. if($type != 'bystory')
  129. {
  130. unset($searchConfig['fields']['story']);
  131. unset($searchConfig['params']['story']);
  132. }
  133. if($product->shadow) unset($searchConfig['fields']['product']);
  134. if($product->type == 'normal')
  135. {
  136. unset($searchConfig['fields']['branch']);
  137. unset($searchConfig['params']['branch']);
  138. }
  139. else
  140. {
  141. $searchConfig['fields']['branch'] = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
  142. $searchConfig['params']['branch']['values'] = $this->testtask->getBranchesByTask($task);;
  143. }
  144. if(!$this->config->testcase->needReview) unset($searchConfig['params']['status']['values']['wait']);
  145. unset($searchConfig['fields']['product']);
  146. $this->loadModel('search')->setSearchParams($searchConfig);
  147. }
  148. /**
  149. * 构建编辑测试单的数据。
  150. * Build data for editing a testtask.
  151. *
  152. * @param int $taskID
  153. * @param int $productID
  154. * @access protected
  155. * @return object
  156. */
  157. protected function buildTaskForEdit($taskID, $productID)
  158. {
  159. $task = form::data($this->config->testtask->form->edit, $taskID)
  160. ->add('id', $taskID)
  161. ->add('product', $productID)
  162. ->stripTags($this->config->testtask->editor->edit['id'], $this->config->allowedTags)
  163. ->get();
  164. /* Fix bug #35419. */
  165. $execution = $this->loadModel('execution')->getByID($task->execution);
  166. if(!$execution)
  167. {
  168. $build = $this->loadModel('build')->getById((int)$task->build);
  169. $task->project = $build->project;
  170. }
  171. else
  172. {
  173. $task->project = $execution->project;
  174. }
  175. $task->members = trim($task->members, ',');
  176. $task = $this->loadModel('file')->processImgURL($task, $this->config->testtask->editor->edit['id'], $this->post->uid);
  177. return $task;
  178. }
  179. /**
  180. * 构建开始测试单的数据。
  181. * Build data for starting a testtask.
  182. *
  183. * @param int $taskID
  184. * @access protected
  185. * @return object
  186. */
  187. protected function buildTaskForStart($taskID)
  188. {
  189. $task = form::data($this->config->testtask->form->start, $taskID)
  190. ->add('id', $taskID)
  191. ->stripTags($this->config->testtask->editor->start['id'], $this->config->allowedTags)
  192. ->get();
  193. return $this->loadModel('file')->processImgURL($task, $this->config->testtask->editor->start['id'], $task->uid);
  194. }
  195. /**
  196. * 构建关闭测试单的数据。
  197. * Build data for closing a testtask.
  198. *
  199. * @param int $taskID
  200. * @access protected
  201. * @return object
  202. */
  203. protected function buildTaskForClose($taskID)
  204. {
  205. $task = form::data($this->config->testtask->form->close, $taskID)
  206. ->add('id', $taskID)
  207. ->stripTags($this->config->testtask->editor->close['id'], $this->config->allowedTags)
  208. ->get();
  209. return $this->loadModel('file')->processImgURL($task, $this->config->testtask->editor->close['id'], $task->uid);
  210. }
  211. /**
  212. * 构建激活测试单的数据。
  213. * Build data for activating a testtask.
  214. *
  215. * @param int $taskID
  216. * @access protected
  217. * @return object
  218. */
  219. protected function buildTaskForActivate($taskID)
  220. {
  221. $task = form::data($this->config->testtask->form->activate, $taskID)
  222. ->add('id', $taskID)
  223. ->stripTags($this->config->testtask->editor->activate['id'], $this->config->allowedTags)
  224. ->get();
  225. return $this->loadModel('file')->processImgURL($task, $this->config->testtask->editor->activate['id'], $task->uid);
  226. }
  227. /**
  228. * 构建阻塞测试单的数据。
  229. * Build data for blocking a testtask.
  230. *
  231. * @param int $taskID
  232. * @access protected
  233. * @return object
  234. */
  235. protected function buildTaskForBlock($taskID)
  236. {
  237. $task = form::data($this->config->testtask->form->block, $taskID)
  238. ->add('id', $taskID)
  239. ->stripTags($this->config->testtask->editor->block['id'], $this->config->allowedTags)
  240. ->get();
  241. return $this->loadModel('file')->processImgURL($task, $this->config->testtask->editor->block['id'], $task->uid);
  242. }
  243. /**
  244. * 构建导入单元测试结果的数据。
  245. * Build data for importing unit test result.
  246. *
  247. * @param int $productID
  248. * @access protected
  249. * @return object
  250. */
  251. protected function buildTaskForImportUnitResult($productID)
  252. {
  253. $task = form::data($this->config->testtask->form->importUnitResult)
  254. ->add('product', $productID)
  255. ->add('auto', 'unit')
  256. ->stripTags($this->config->testtask->editor->importunitresult['id'], $this->config->allowedTags)
  257. ->get();
  258. return $this->loadModel('file')->processImgURL($task, $this->config->testtask->editor->importunitresult['id'], $task->uid);
  259. }
  260. /**
  261. * 检查编辑的测试单数据是否符合要求。
  262. * Check data for editing a testtask.
  263. *
  264. * @param object $task
  265. * @access protected
  266. * @return void
  267. */
  268. protected function checkTaskForEdit($task)
  269. {
  270. $requiredErrors = array();
  271. /* Check required fields of editing task . */
  272. foreach(explode(',', $this->config->testtask->edit->requiredFields) as $requiredField)
  273. {
  274. if(!isset($task->{$requiredField}) || strlen(trim($task->{$requiredField})) == 0) $requiredErrors[$requiredField][] = sprintf($this->lang->error->notempty, isset($this->lang->testtask->{$requiredField}) ? $this->lang->testtask->$requiredField : $requiredField);
  275. }
  276. if(!empty($requiredErrors)) dao::$errors = $requiredErrors;
  277. if($task->end && $task->begin > $task->end) dao::$errors['end'][] = sprintf($this->lang->error->ge, $this->lang->testtask->end, $this->lang->testtask->begin);
  278. return !dao::isError();
  279. }
  280. /**
  281. * 分配变量给一个测试单的用例列表页。
  282. * Assign variables for cases page of a testtask.
  283. *
  284. * @param object $produc
  285. * @param object $testtask
  286. * @param array $runs
  287. * @param array $scenes
  288. * @param int $moduleID
  289. * @param string $browseType
  290. * @param int $param
  291. * @param string $orderBy
  292. * @param object $pager
  293. * @access public
  294. * @return void
  295. * @param object $product
  296. */
  297. public function assignForCases($product, $testtask, $runs, $scenes, $moduleID, $browseType, $param, $orderBy, $pager)
  298. {
  299. $suites = $this->loadModel('testsuite')->getSuitePairs($product->id);
  300. /* Get assignedToList based on the execution. */
  301. $execution = $this->loadModel('execution')->getById($testtask->execution);
  302. if($execution and $execution->acl == 'private')
  303. {
  304. $assignedToList = $this->loadModel('user')->getTeamMemberPairs($execution->id, 'execution', 'nodeleted');
  305. }
  306. else
  307. {
  308. $assignedToList = $this->loadModel('user')->getPairs('noclosed|noletter|nodeleted|qafirst');
  309. }
  310. $this->setDropMenu($product->id, $testtask);
  311. $showModule = $this->loadModel('setting')->getItem("owner={$this->app->user->account}&module=testtask&section=cases&key=showModule");
  312. $runs = $this->loadModel('testcase')->appendData($runs, 'run');
  313. $runList = array_merge($runs, $scenes);
  314. if($this->config->edition != 'open')
  315. {
  316. $caseRelatedObjectList = $this->loadModel('custom')->getRelatedObjectList(array_column($runList, 'case'), 'testcase', 'byRelation', true);
  317. foreach($runList as $run)
  318. {
  319. if(!empty($run->isScene)) continue;
  320. $run->caseID = $run->case;
  321. $run->relatedObject = zget($caseRelatedObjectList, $run->case, 0);
  322. }
  323. }
  324. $this->view->title = $product->name . $this->lang->hyphen . $this->lang->testtask->cases;
  325. $this->view->runs = $runList;
  326. $this->view->users = $this->loadModel('user')->getPairs('noclosed|qafirst|noletter');
  327. $this->view->moduleTree = $this->loadModel('tree')->getTreeMenu($product->id, 'case', 0, array('treeModel', 'createTestTaskLink'), (string)$testtask->id, $testtask->branch ? $testtask->branch : '0');
  328. $this->view->automation = $this->loadModel('zanode')->getAutomationByProduct($product->id);
  329. $this->view->suiteName = $browseType == 'bysuite' ? zget($suites, $param, $this->lang->testtask->browseBySuite) : $this->lang->testtask->browseBySuite;
  330. $this->view->canBeChanged = common::canBeChanged('testtask', $testtask);
  331. $this->view->assignedToList = $assignedToList;
  332. $this->view->suites = $suites;
  333. $this->view->productID = $product->id;
  334. $this->view->product = $product;
  335. $this->view->task = $testtask;
  336. $this->view->moduleID = $moduleID;
  337. $this->view->browseType = $browseType;
  338. $this->view->param = $param;
  339. $this->view->orderBy = $orderBy;
  340. $this->view->pager = $pager;
  341. $this->view->branch = $testtask->branch;
  342. $this->view->modulePairs = $showModule ? $this->tree->getModulePairs($product->id, 'case', $showModule) : array();
  343. $this->view->iscenes = $this->testcase->getSceneMenu($product->id, $moduleID);
  344. $this->view->branches = $this->loadModel('branch')->getPairs($product->id);
  345. }
  346. /**
  347. * 分配变量给创建测试单页面。
  348. * Assign variables for creating page.
  349. *
  350. * @param int $productID$product
  351. * @param int $projectID
  352. * @param int $executionID
  353. * @param int $build
  354. * @access protected
  355. * @return void
  356. */
  357. protected function assignForCreate($productID, $projectID, $executionID, $build)
  358. {
  359. $objectType = 'project';
  360. $objectID = $projectID;
  361. if($projectID)
  362. {
  363. /* 如果是无迭代项目,则获取影子迭代的迭代ID。*/
  364. /* If there is no sprint in the project, get the ID of the shadow sprint. */
  365. $project = $this->loadModel('project')->getByID($projectID);
  366. if($project && !$project->multiple) $this->view->noMultipleExecutionID = $this->loadModel('execution')->getNoMultipleID($project->id);
  367. }
  368. if($executionID)
  369. {
  370. /* 根据所选迭代的类型,调整表单字段的文本显示。*/
  371. /* Adjust the display value based on the type of sprint selected. */
  372. $execution = $this->loadModel('execution')->getByID($executionID);
  373. if(!empty($execution) && $execution->type == 'kanban') $this->lang->testtask->execution = str_replace($this->lang->execution->common, $this->lang->kanban->common, $this->lang->testtask->execution);
  374. $objectType = 'execution';
  375. $objectID = $executionID;
  376. }
  377. /* 如果测试单所属产品在产品键值对中不存在,将其加入。*/
  378. /* Prepare the product key-value pairs. */
  379. $product = $this->loadModel('product')->getByID($productID);
  380. if(!isset($this->products[$productID]) && !empty($product)) $this->products[$productID] = $product->name;
  381. $this->view->title = $this->lang->testtask->create;
  382. $this->view->productID = $productID;
  383. $this->view->product = $product;
  384. $this->view->executions = $productID ? $this->product->getExecutionPairsByProduct($productID, '', $projectID, 'stagefilter') : array();
  385. $this->view->builds = $productID ? $this->loadModel('build')->getBuildPairs(array($productID), 'all', 'notrunk,withexecution', $objectID, $objectType, '', false) : array();
  386. $this->view->testreports = $this->loadModel('testreport')->getPairs($productID);
  387. $this->view->users = $this->loadModel('user')->getPairs('noclosed|qdfirst|nodeleted');
  388. $this->view->projectID = $projectID;
  389. $this->view->executionID = $executionID;
  390. $this->view->build = $build;
  391. }
  392. /**
  393. * 分配变量给编辑测试单页面。
  394. * Assign variables for editing page.
  395. *
  396. * @param object $task
  397. * @param int $productID
  398. * @access protected
  399. * @return void
  400. */
  401. protected function assignForEdit($task, $productID)
  402. {
  403. $this->loadModel('project');
  404. $productID = $productID;
  405. $projectID = $this->lang->navGroup->testtask == 'qa' ? 0 : $this->session->project;
  406. $executionID = $task->execution;
  407. $executions = empty($productID) ? array() : $this->loadModel('product')->getExecutionPairsByProduct($productID, '0', $projectID, 'stagefilter');
  408. if($executionID && !isset($executions[$executionID]))
  409. {
  410. $execution = $this->loadModel('execution')->getById($executionID);
  411. $executions[$executionID] = $execution->name;
  412. if(empty($execution->multiple))
  413. {
  414. $project = $this->project->getById($execution->project);
  415. $executions[$executionID] = "{$project->name}({$this->lang->project->disableExecution})";
  416. }
  417. }
  418. if(!isset($this->products[$productID]))
  419. {
  420. $product = $this->loadModel('product')->getByID($productID);
  421. $this->products[$productID] = $product->name;
  422. }
  423. $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->testtask->edit;
  424. $this->view->testtask = $task;
  425. $this->view->project = $this->project->getByID($projectID);
  426. $this->view->productID = $productID;
  427. $this->view->executions = $executions;
  428. $this->view->executionID = $executionID;
  429. $this->view->builds = empty($productID) ? array() : $this->loadModel('build')->getBuildPairs(array($productID), 'all', 'noempty,notrunk,withexecution', $executionID ? $executionID : $task->project, $executionID ? 'execution' : 'project', $task->build, false);
  430. $this->view->testreports = $this->loadModel('testreport')->getPairs($task->product, $task->testreport);
  431. $this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed', $task->owner);
  432. $this->view->contactLists = $this->user->getContactLists();
  433. }
  434. /**
  435. * 分配变量给一个测试用例的执行页面。
  436. * Assign variables for runCase page of a test case.
  437. *
  438. * @param object $run
  439. * @param object $preAndNext
  440. * @param int $runID
  441. * @param int $caseID
  442. * @param int $version
  443. * @param string $confirm
  444. * @access protected
  445. * @return void
  446. */
  447. protected function assignForRunCase($run, $preAndNext, $runID, $caseID, $version, $confirm)
  448. {
  449. $preLink = '';
  450. $nextLink = '';
  451. if($preAndNext->pre && $this->app->tab != 'my')
  452. {
  453. $preCaseRunID = $runID ? $preAndNext->pre->id : 0;
  454. $preCaseID = $preCaseRunID ? $preAndNext->pre->case : $preAndNext->pre->id;
  455. $preLink = inlink('runCase', "runID={$preCaseRunID}&caseID={$preCaseID}&version={$preAndNext->pre->version}");
  456. }
  457. if($preAndNext->next && $this->app->tab != 'my')
  458. {
  459. $nextCaseRunID = $runID ? $preAndNext->next->id : 0;
  460. $nextCaseID = $nextCaseRunID ? $preAndNext->next->case : $preAndNext->next->id;
  461. $nextLink = inlink('runCase', "runID={$nextCaseRunID}&caseID={$nextCaseID}&version={$preAndNext->next->version}");
  462. }
  463. $this->view->title = $this->lang->testtask->lblRunCase;
  464. $this->view->users = $this->loadModel('user')->getPairs('noclosed, noletter');
  465. $this->view->run = $run;
  466. $this->view->runID = $runID;
  467. $this->view->caseID = $caseID;
  468. $this->view->version = $version;
  469. $this->view->confirm = $confirm;
  470. $this->view->preLink = $preLink;
  471. $this->view->nextLink = $nextLink;
  472. }
  473. /**
  474. * 根据不同情况获取产品键值对,大多用于1.5级导航。
  475. * Get product key-value pairs according to different situations.
  476. *
  477. * @access protected
  478. * @return array
  479. */
  480. protected function getProducts()
  481. {
  482. if(commonModel::isTutorialMode()) return $this->loadModel('tutorial')->getProductPairs();
  483. /* 如果是在非弹窗页面的项目或执行应用下打开的测试单,则获取当前项目或执行对应的产品。*/
  484. /* If the testtask is opened under a project or execution application on a non-pop-up page, get the current project or execution corresponding product. */
  485. $tab = $this->app->tab;
  486. if(!isonlybody() && ($tab == 'project' || $tab == 'execution')) return $this->loadModel('product')->getProducts($this->session->$tab, 'all', '', false);
  487. /* 如果是在弹窗页面或者测试应用下打开的测试单,则获取所有产品。*/
  488. /* If the testtask is opened on a pop-up page or test application, get all products. */
  489. return $this->loadModel('product')->getPairs('', 0, '', 'all');
  490. }
  491. /**
  492. * 统计不同状态测试单的数量,用于列表底部信息展示。
  493. * Count the number of testtasks in different statuses for information display at the bottom of the browse page.
  494. *
  495. * @param array $testtasks
  496. * @access protected
  497. * @return void
  498. */
  499. protected function prepareSummaryForBrowse($testtasks)
  500. {
  501. $waitCount = 0;
  502. $testingCount = 0;
  503. $blockedCount = 0;
  504. $doneCount = 0;
  505. foreach($testtasks as $testtask)
  506. {
  507. if($testtask->rawStatus == 'wait') $waitCount ++;
  508. if($testtask->rawStatus == 'doing') $testingCount ++;
  509. if($testtask->rawStatus == 'blocked') $blockedCount ++;
  510. if($testtask->rawStatus == 'done') $doneCount ++;
  511. if($testtask->build == 'trunk' || empty($testtask->buildName)) $testtask->buildName = $this->lang->trunk;
  512. }
  513. $this->view->allSummary = sprintf($this->lang->testtask->allSummary, count($testtasks), $waitCount, $testingCount, $blockedCount, $doneCount);
  514. $this->view->pageSummary = sprintf($this->lang->testtask->pageSummary, count($testtasks));
  515. }
  516. /**
  517. * 获取批量执行的用例。
  518. * Get cases to run.
  519. *
  520. * @param int $productID
  521. * @param string $orderBy
  522. * @param string $from
  523. * @param int $testID
  524. * @param string $confirm
  525. * @param array $caseIdList
  526. * @access protected
  527. * @return array
  528. * @param int $taskID
  529. */
  530. protected function prepareCasesForBatchRun($productID, $orderBy, $from, $taskID, $confirm, $caseIdList)
  531. {
  532. $this->setMenu($productID, 0, (int)$this->session->project, (int)$this->session->execution);
  533. $menu = isset($this->lang->{$this->app->tab}->menu) ? $this->lang->{$this->app->tab}->menu : array();
  534. if($this->app->tab != 'qa')
  535. {
  536. $menu = isset($menu->qa) ? $menu->qa['subMenu'] : array();
  537. if(isset($menu->testtask)) $menu->testtask['subModule'] = '';
  538. }
  539. $menu->{$from}['subModule'] .= ',testtask';
  540. $orderBy = str_replace('caseID_', 'id_', $orderBy);
  541. $cases = $this->dao->select('*')->from(TABLE_CASE)
  542. ->where('id')->in($caseIdList)
  543. ->beginIF($confirm == 'yes')->andWhere('auto')->ne('auto')->fi()
  544. ->orderBy($orderBy)
  545. ->fetchAll('id', false);
  546. if($from != 'testtask') return $cases;
  547. /* 如果批量执行的用例来自测试单,检查这些用例的版本,如果不是最新版就移除它们。*/
  548. /* If cases come from a testtask, check the version of these cases, if not the latest version, remove them. */
  549. $runs = $this->dao->select('`case`, version')->from(TABLE_TESTRUN)->where('`case`')->in(array_keys($cases))->andWhere('task')->eq($taskID)->fetchPairs();
  550. foreach($cases as $caseID => $case)
  551. {
  552. if(isset($runs[$caseID]) && $runs[$caseID] < $case->version) unset($cases[$caseID]);
  553. }
  554. $testtask = $this->testtask->fetchByID($taskID);
  555. $this->view->executionID = $testtask->execution;
  556. return $cases;
  557. }
  558. /**
  559. * 处理单元测试用例列表页面的测试用例的跨行合并属性供前端组件分页使用。
  560. * Process the rowspan property of cases for unitCases page for use by front-end component groupings.
  561. *
  562. * @param array $runs
  563. * @access protected
  564. * @return array
  565. */
  566. protected function processRowspanForUnitCases($runs)
  567. {
  568. /* 将测试用例数据按照套件进行分组,方便按套件计算数量。 */
  569. /* Group test cases according to suites to facilitate calculation of quantities by suite. */
  570. $groupCases = array();
  571. foreach($runs as $run) $groupCases[$run->suite][] = $run;
  572. /* 将每个套件下的总用例数量赋予每个套件的第一条测试用例。*/
  573. /* Assign the total number of test cases under each suite to the first test case of each suite. */
  574. $suite = null;
  575. foreach($runs as $run)
  576. {
  577. $run->rowspan = 0;
  578. if($suite !== $run->suite && !empty($groupCases[$run->suite]))
  579. {
  580. $suite = $run->suite;
  581. $run->rowspan = count($groupCases[$run->suite]);
  582. }
  583. }
  584. return $runs;
  585. }
  586. /**
  587. * 处理分组查看页面的测试用例的跨行合并属性供前端组件分组使用。
  588. * Process the rowspan property of cases for groupCase page for use by front-end component groupings.
  589. *
  590. * @param array $cases
  591. * @param int $build
  592. * @access protected
  593. * @return array
  594. */
  595. protected function processRowspanForGroupCase($cases, $build)
  596. {
  597. $groupCases = array();
  598. foreach($cases as $case) $groupCases[$case->story][] = $case;
  599. if($build)
  600. {
  601. $buildStories = $this->dao->select('stories')->from(TABLE_BUILD)->where('id')->eq($build)->fetch('stories');
  602. $storyIdList = array_filter(array_diff(explode(',', $buildStories), array_keys($groupCases)));
  603. if($storyIdList)
  604. {
  605. $stories = $this->dao->select('id,title')->from(TABLE_STORY)->where('deleted')->eq('0')->andWhere('id')->in($storyIdList)->fetchAll();
  606. foreach($stories as $story) $groupCases[$story->id][] = $story;
  607. }
  608. }
  609. /* 将每个需求的总用例数量赋予每个需求的第一条测试用例。*/
  610. /* Assign the total number of test cases under each story to the first test case of each story. */
  611. $story = null;
  612. foreach($cases as $case)
  613. {
  614. $case->rowspan = 0;
  615. if($story !== $case->story && !empty($groupCases[$case->story]))
  616. {
  617. $story = $case->story;
  618. $case->rowspan = count($groupCases[$case->story]);
  619. unset($groupCases[$case->story]);
  620. }
  621. }
  622. /* 将没有用例的需求添加到用例列表中。 */
  623. /* Add the stories without test cases to the test case list. */
  624. foreach($groupCases as $stories)
  625. {
  626. $story = reset($stories);
  627. $case = new stdclass();
  628. $case->storyTitle = $story->title;
  629. $cases[] = $case;
  630. }
  631. return $cases;
  632. }
  633. /**
  634. * 检测要执行的测试用例是否是自动化测试用例并根据用户确认结果执行不同的操作。
  635. * Detect whether the test case to be executed is an automated test case and perform different operations based on the user confirmation results.
  636. *
  637. * @param object $run
  638. * @param int $runID
  639. * @param int $caseID
  640. * @param int $version
  641. * @param string $confirm
  642. * @access protected
  643. * @return void
  644. */
  645. protected function checkAndExecuteAutomatedTest($run, $runID, $caseID, $version, $confirm)
  646. {
  647. /* 如果要执行的测试用例是自动化测试用例,并且设置了自动化测试的参数配置,并且用户尚未确认,则弹窗让用户确认。*/
  648. /* If the test case to be executed is an automated test case, and the parameter configuration of the automated test is set, and the user has not confirmed it, a pop-up window will pop up for the user to confirm. */
  649. $cancelURL = inlink('runCase', "runID=$runID&caseID=$caseID&version=$version&confirm=no");
  650. $automation = $this->loadModel('zanode')->getAutomationByProduct($run->case->product);
  651. if($run->case->auto == 'auto' && $confirm == '')
  652. {
  653. if(!$automation)
  654. {
  655. if(helper::isAjaxRequest() && isInModal()) $this->locate($cancelURL);;
  656. return $this->send(array('load' => $cancelURL));
  657. }
  658. $confirmURL = inlink('runCase', "runID=$runID&caseID=$caseID&version=$version&confirm=yes");
  659. if(helper::isAjaxRequest() && isInModal()) return print(js::start() . "zui.Modal.hide($(document).find('.modal')); zui.Modal.confirm('{$this->lang->zanode->runCaseConfirm}').then((res) => {if(res){ openUrl({url: '{$confirmURL}', load: 'modal', size: 'lg'});}else{ openUrl({url: '{$cancelURL}', load: 'modal', size: 'lg'});}});" . js::end());
  660. return $this->send(array('result' => 'fail', 'load' => array('confirm' => $this->lang->zanode->runCaseConfirm, 'confirmed' => $confirmURL, 'canceled' => $cancelURL)));
  661. }
  662. /* 用户确认后执行自动化测试的相关操作。*/
  663. /* Perform automated testing related operations after user confirmation. */
  664. if($confirm == 'yes')
  665. {
  666. if(!$automation)
  667. {
  668. if(helper::isAjaxRequest() && isInModal()) $this->locate($cancelURL);;
  669. return $this->send(array('load' => $cancelURL));
  670. }
  671. $resultID = $this->testtask->initResultForAutomatedTest($runID, $caseID, $run->case->version, $automation->node);
  672. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError(), 'load' => $this->createLink('zanode', 'browse')));
  673. $this->zanode->runZTFScript($automation->id, $caseID, $resultID);
  674. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError(), 'load' => $this->createLink('zanode', 'browse')));
  675. if($this->server->request_method == 'POST' && empty($_POST)) return $this->sendSuccess();
  676. }
  677. }
  678. /**
  679. * 根据测试用例的执行结果返回不同的内容。
  680. * Return different content based on the execution results of the test case.
  681. *
  682. * @param string $caseResult
  683. * @param object $preAndNext
  684. * @param object $run
  685. * @param int $caseID
  686. * @param int $version
  687. * @access protected
  688. * @return void
  689. */
  690. protected function responseAfterRunCase($caseResult, $preAndNext, $run, $caseID, $version)
  691. {
  692. $runID = !empty($run->id) ? $run->id : 0;
  693. if(!empty($run->task)) $this->testtask->updateStatus((int)$run->task);
  694. if($caseResult == 'fail')
  695. {
  696. $link = inlink('runCase', "runID={$runID}&caseID={$caseID}&version={$version}");
  697. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'callback' => "loadModal('$link', 'runCaseModal')"));
  698. }
  699. /* set cookie for ajax load caselist when close colorbox. */
  700. helper::setcookie('selfClose', 1, 0);
  701. if($preAndNext->next && $this->app->tab != 'my')
  702. {
  703. $nextRunID = $runID ? $preAndNext->next->id : 0;
  704. $nextCaseID = $runID ? $preAndNext->next->case : $preAndNext->next->id;
  705. $nextVersion = $preAndNext->next->version;
  706. $link = inlink('runCase', "runID={$nextRunID}&caseID={$nextCaseID}&version={$nextVersion}");
  707. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'callback' => "loadModal('$link', 'runCaseModal')"));
  708. }
  709. }
  710. /**
  711. * 设置测试单下拉。
  712. * Set testtask drop menu.
  713. *
  714. * @param string $caseResult
  715. * @param object $preAndNext
  716. * @param int $runID
  717. * @param int $caseID
  718. * @param int $version
  719. * @access protected
  720. * @return void
  721. * @param object $task
  722. * @param int $productID
  723. */
  724. public function setDropMenu($productID, $task)
  725. {
  726. /* Set drop menu. */
  727. $objectType = $objectID = '';
  728. if(in_array($this->app->tab, array('project', 'execution')))
  729. {
  730. $objectType = $this->app->tab;
  731. $idField = $objectType . 'ID';
  732. $objectID = $task->{$this->app->tab};
  733. $this->view->{$idField} = $objectID;
  734. $this->view->{$objectType} = $this->loadModel($objectType)->getByID($objectID);
  735. }
  736. $this->view->switcherParams = "productID={$productID}&branch=&taskID={$task->id}&module=testtask&method={$this->app->rawMethod}&objectType={$objectType}&objectID={$objectID}";
  737. $this->view->switcherText = $task->name;
  738. $this->view->switcherObjectID = $task->id;
  739. }
  740. }