control.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. <?php
  2. /**
  3. * The control file of testsuite 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 testsuite
  9. * @link https://www.zentao.net
  10. */
  11. class testsuite extends control
  12. {
  13. /**
  14. * 所有产品。
  15. * All products.
  16. *
  17. * @var array
  18. * @access public
  19. */
  20. public $products = array();
  21. /**
  22. * 构造函数
  23. *
  24. * 1.加载其他model类。
  25. * 2.获取产品,并输出到视图。
  26. *
  27. * The construct function.
  28. *
  29. * 1. Load model of other modules.
  30. * 2. Get products and assign to view.
  31. *
  32. * @param string $moduleName
  33. * @param string $methodName
  34. * @access public
  35. * @return void
  36. */
  37. public function __construct($moduleName = '', $methodName = '')
  38. {
  39. parent::__construct($moduleName, $methodName);
  40. $this->view->products = $this->products = $this->loadModel('product')->getPairs('', 0, '', 'all');
  41. if(empty($this->products) && (helper::isAjaxRequest('zin') || helper::isAjaxRequest('fetch')))
  42. {
  43. $tab = $this->app->tab == 'project' || $this->app->tab == 'execution' ? $this->app->tab : 'qa';
  44. $objectID = $tab == 'project' || $tab == 'execution' ? $this->session->{$tab} : 0;
  45. $this->locate($this->createLink('product', 'showErrorNone', "moduleName={$tab}&activeMenu=testsuite&objectID=$objectID"));
  46. }
  47. }
  48. /**
  49. * 索引页,导向browse页面。
  50. * Index page, header to browse.
  51. *
  52. * @access public
  53. * @return void
  54. */
  55. public function index()
  56. {
  57. $this->locate($this->inlink('browse'));
  58. }
  59. /**
  60. * 测试套件列表。
  61. * Browse test suites.
  62. *
  63. * @param int $productID
  64. * @param string $type
  65. * @param string $orderBy
  66. * @param int $recTotal
  67. * @param int $recPerPage
  68. * @param int $pageID
  69. * @access public
  70. * @return void
  71. */
  72. public function browse($productID = 0, $type = 'all', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
  73. {
  74. /* 将当前URI存入SESSION。 */
  75. /* Save session. */
  76. $this->session->set('testsuiteList', $this->app->getURI(true), 'qa');
  77. /* 设置1.5级导航。 */
  78. /* Set level 1.5 navigation */
  79. $productID = $this->product->checkAccess($productID, $this->products);
  80. $this->loadModel('qa')->setMenu($productID);
  81. /* 初始化分页。 */
  82. /* Load pager. */
  83. $this->app->loadClass('pager', true);
  84. $pager = pager::init($recTotal, $recPerPage, $pageID);
  85. /* 生成排序规则。 */
  86. /* Generate the sort rules. */
  87. $sort = common::appendOrder($orderBy);
  88. /* 根据产品名称获取套件,如果查询为空并且不在第一页,则初始化至当前页码到第一页。 */
  89. /* Get the package according to the product name, if the query is empty and not on the first page, initialize to the current page number to the first page. */
  90. $productName = isset($this->products[$productID]) ? $this->products[$productID] : '';
  91. $suites = $this->testsuite->getSuites($productID, $sort, $pager, $type);
  92. if(empty($suites) && $pageID > 1)
  93. {
  94. $pager = pager::init(0, $recPerPage, 1);
  95. $suites = $this->testsuite->getSuites($productID, $sort, $pager, $type);
  96. }
  97. /* 获取公共和私有的套件数量。 */
  98. /* Get the number of public and private suites. */
  99. $totalNum = count($suites);
  100. $privateNum = count(array_filter($suites, function($suite){return $suite->type == 'private';}));
  101. $publicNum = $totalNum - $privateNum;
  102. $summary = sprintf($this->lang->testsuite->summary, $totalNum, $publicNum, $privateNum);
  103. $this->view->title = $productName . $this->lang->testsuite->common;
  104. $this->view->orderBy = $orderBy;
  105. $this->view->suites = $suites;
  106. $this->view->type = $type;
  107. $this->view->summary = $summary;
  108. $this->view->pager = $pager;
  109. $this->view->product = $this->product->getByID($productID);
  110. $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
  111. $this->display();
  112. }
  113. /**
  114. * 创建一个测试套件。
  115. * Create a test suite.
  116. *
  117. * @param int $productID
  118. * @access public
  119. * @return void
  120. */
  121. public function create($productID)
  122. {
  123. if(!empty($_POST))
  124. {
  125. $suiteData = form::data($this->config->testsuite->form->create)
  126. ->setIF($this->lang->navGroup->testsuite != 'qa', 'project', $this->session->project)
  127. ->add('product', $productID)
  128. ->get();
  129. $suite = $this->loadModel('file')->processImgURL($suiteData, $this->config->testsuite->editor->create['id'], $this->post->uid);
  130. $suiteID = $this->testsuite->create($suite);
  131. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  132. $this->file->updateObjectID($this->post->uid, $suiteID, 'testsuite');
  133. $message = $this->executeHooks($suiteID) ? : $this->lang->testsuite->successSaved;
  134. if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $message, 'id' => $suiteID));
  135. return $this->send(array('result' => 'success', 'message' => $message, 'locate' => $this->inlink('browse', "productID=$productID")));
  136. }
  137. /* 设置1.5级导航。 */
  138. /* Set level 1.5 navigation */
  139. $productID = $this->product->checkAccess($productID, $this->products);
  140. $this->loadModel('qa')->setMenu($productID);
  141. $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->testsuite->create;
  142. $this->view->productID = $productID;
  143. $this->display();
  144. }
  145. /**
  146. * 查看一个测试套件详情。
  147. * View a test suite.
  148. *
  149. * @param int $suiteID
  150. * @param string $orderBy
  151. * @param int $recTotal
  152. * @param int $recPerPage
  153. * @param int $pageID
  154. * @access public
  155. * @return void
  156. */
  157. public function view($suiteID, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 10, $pageID = 1)
  158. {
  159. /* 检查用户访问权限。 */
  160. /* Check user access rights. */
  161. $suite = $this->testsuiteZen->checkTestsuiteAccess($suiteID);
  162. /* 设置1.5级导航。 */
  163. /* Set level 1.5 navigation */
  164. $productID = $this->product->checkAccess($suite->product, $this->products);
  165. $this->loadModel('qa')->setMenu($productID);
  166. /* 当前URI存入session。 */
  167. /* Sava the uri of current page into session. */
  168. $this->session->set('caseList', $this->app->getURI(true), 'qa');
  169. /* 生成排序规则。 */
  170. /* Generate the sort rules. */
  171. $sort = common::appendOrder($orderBy);
  172. /* 初始化该套件关联用例的分页器。 */
  173. /* Initalizes the paginator for this suites's associated use case. */
  174. $this->app->loadClass('pager', true);
  175. $pager = pager::init($recTotal, $recPerPage, $pageID);
  176. $this->executeHooks($suiteID);
  177. $this->view->title = "SUITE #$suite->id $suite->name";
  178. $this->view->productID = $productID;
  179. $this->view->suite = $suite;
  180. $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
  181. $this->view->actions = $this->loadModel('action')->getList('testsuite', $suiteID);
  182. $this->view->cases = $this->testsuite->getLinkedCases($suiteID, $sort, $pager);
  183. $this->view->orderBy = $orderBy;
  184. $this->view->pager = $pager;
  185. $this->view->modules = $this->loadModel('tree')->getOptionMenu($suite->product, 'case', 0, 'all');
  186. $this->view->branches = $this->loadModel('branch')->getPairs($suite->product);
  187. $this->view->canBeChanged = common::canBeChanged('testsuite', $suite);
  188. $this->view->automation = $this->loadModel('zanode')->getAutomationByProduct($productID);
  189. $this->display();
  190. }
  191. /**
  192. * 修改一个测试套件。
  193. * Edit a test suite.
  194. *
  195. * @param int $suiteID
  196. * @access public
  197. * @return void
  198. */
  199. public function edit($suiteID)
  200. {
  201. /* 检查用户访问权限。 */
  202. /* Check user access rights. */
  203. $suite = $this->testsuiteZen->checkTestsuiteAccess($suiteID);
  204. if(!empty($_POST))
  205. {
  206. /* 根据suiteID更新数据,如果更新成功,则记录日志。 */
  207. /* Update the data according to the suiteID, and record the log if the update is successful. */
  208. $suite = form::data($this->config->testsuite->form->edit, $suiteID)->add('id', $suiteID)->get();
  209. $changes = $this->testsuite->update($suite, $this->post->uid);
  210. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  211. if($changes)
  212. {
  213. $actionID = $this->loadModel('action')->create('testsuite', $suiteID, 'edited');
  214. $this->action->logHistory($actionID, $changes);
  215. }
  216. $message = $this->executeHooks($suiteID) ? : $this->lang->testsuite->successSaved;
  217. return $this->send(array('result' => 'success', 'message' => $message, 'locate' => inlink('view', "suiteID={$suiteID}")));
  218. }
  219. /* 设置1.5级导航。 */
  220. /* Set level 1.5 navigation */
  221. $productID = $this->product->checkAccess($suite->product, $this->products);
  222. $this->loadModel('qa')->setMenu($productID);
  223. $this->view->title = $this->products[$productID] . $this->lang->hyphen . $this->lang->testsuite->edit;
  224. $this->view->suite = $suite;
  225. $this->view->productID = $productID;
  226. $this->display();
  227. }
  228. /**
  229. * 删除一个测试套件。
  230. * Delete a test suite.
  231. *
  232. * @param int $suiteID
  233. * @access public
  234. * @return void
  235. */
  236. public function delete($suiteID)
  237. {
  238. /* 检查用户访问权限。 */
  239. /* Check user access rights. */
  240. $this->testsuiteZen->checkTestsuiteAccess($suiteID);
  241. $this->testsuite->delete(TABLE_TESTSUITE, $suiteID);
  242. $message = $this->executeHooks($suiteID) ? : '';
  243. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  244. return $this->send(array('result' => 'success', 'message' => $message, 'load' => true));
  245. }
  246. /**
  247. * 关联用例到一个测试套件。
  248. * Link cases to a test suite.
  249. *
  250. * @param int $suiteID
  251. * @param string $browseType
  252. * @param int $param
  253. * @param int $recTotal
  254. * @param int $recPerPage
  255. * @param int $pageID
  256. * @access public
  257. * @return void
  258. */
  259. public function linkCase($suiteID, $browseType = 'all', $param = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1)
  260. {
  261. /* 当前页面URI存入session。 */
  262. /* Save the URI of current page into session. */
  263. $this->session->set('caseList', $this->app->getURI(true), 'qa');
  264. if(!empty($_POST))
  265. {
  266. $caseData = form::data($this->config->testsuite->form->linkCase)->get();
  267. $this->testsuite->linkCase($suiteID, $caseData->cases, $caseData->version);
  268. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  269. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => inlink('view', "suiteID=$suiteID")));
  270. }
  271. $suite = $this->testsuite->getById($suiteID);
  272. /* 设置1.5级导航。 */
  273. /* Set level 1.5 navigation */
  274. $productID = $this->product->checkAccess($suite->product, $this->products);
  275. $this->loadModel('qa')->setMenu($productID);
  276. /* 初始化分页。 */
  277. /* Load pager. */
  278. $this->app->loadClass('pager', $static = true);
  279. $pager = pager::init($recTotal, $recPerPage, $pageID);
  280. /* 初始化表单搜索参数。 */
  281. /* Init form search parameters. */
  282. $this->loadModel('testcase');
  283. $this->config->testcase->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'case', 0, 'all');
  284. $this->config->testcase->search['params']['lib']['values'] = $this->loadModel('caselib')->getLibraries();
  285. $this->config->testcase->search['params']['story']['values'] = array('' => '') + $this->testsuite->getCaseLinkedStories($productID);
  286. $this->config->testcase->search['module'] = 'testsuite';
  287. $this->config->testcase->search['actionURL'] = inlink('linkCase', "suiteID=$suiteID&browseType=bySearch&param=myQueryID");
  288. $scene = $this->testcase->getSceneMenu($productID);
  289. $this->config->testcase->search['params']['scene']['values'] = $scene;
  290. unset($this->config->testcase->search['fields']['product']);
  291. unset($this->config->testcase->search['params']['product']);
  292. unset($this->config->testcase->search['fields']['branch']);
  293. unset($this->config->testcase->search['params']['branch']);
  294. if(!$this->config->testcase->needReview) unset($this->config->testcase->search['params']['status']['values']['wait']);
  295. $this->loadModel('search')->setSearchParams($this->config->testcase->search);
  296. $this->view->title = $suite->name . $this->lang->hyphen . $this->lang->testsuite->linkCase;
  297. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  298. $this->view->cases = $this->testsuite->getUnlinkedCases($suite, $browseType, $param, $pager);
  299. $this->view->suiteID = $suiteID;
  300. $this->view->param = $param;
  301. $this->view->pager = $pager;
  302. $this->view->suite = $suite;
  303. $this->view->productID = $productID;
  304. $this->view->browseType = $browseType;
  305. $this->display();
  306. }
  307. /**
  308. * 从测试套件中移除一个用例。
  309. * Remove a case from test suite.
  310. *
  311. * @param int $suiteID
  312. * @param int $caseID
  313. * @access public
  314. * @return void
  315. */
  316. public function unlinkCase($suiteID, $caseID)
  317. {
  318. $this->testsuite->deleteCaseBySuiteID(array($caseID), $suiteID);
  319. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  320. return $this->send(array('result' => 'success', 'load' => true));
  321. }
  322. /**
  323. * 批量移除关联用例。
  324. * Batch unlink cases.
  325. *
  326. * @param int $suiteID
  327. * @access public
  328. * @return void
  329. */
  330. public function batchUnlinkCases($suiteID)
  331. {
  332. $caseIDList = zget($_POST, 'caseIdList', array());
  333. $this->testsuite->deleteCaseBySuiteID($caseIDList, $suiteID);
  334. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  335. return $this->send(array('result' => 'success', 'load' => true));
  336. }
  337. /**
  338. * 确认用例变更。
  339. * Confirm testcase changed.
  340. *
  341. * @param int $caseID
  342. * @param int $suiteID
  343. * @param string $from view|list
  344. * @access public
  345. * @return void
  346. */
  347. public function confirmCaseChange($caseID, $suiteID = 0, $from = 'list')
  348. {
  349. $case = $this->loadModel('testcase')->getById($caseID);
  350. $this->dao->update(TABLE_SUITECASE)->set('version')->eq($case->version)->where('suite')->eq($suiteID)->andWhere('`case`')->eq($caseID)->exec();
  351. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $from == 'list' ? true : $this->createLink('testcase', 'view', "caseID={$caseID}&version={$case->version}&from=testsuite&taskID=0&stepsType=&suiteID={$suiteID}")));
  352. }
  353. }