test_pagure_flask_ui_roadmap.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2016-2018 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. __requires__ = ['SQLAlchemy >= 0.8']
  8. import pkg_resources
  9. import datetime
  10. import json
  11. import unittest
  12. import shutil
  13. import sys
  14. import tempfile
  15. import os
  16. import pygit2
  17. from mock import patch
  18. sys.path.insert(0, os.path.join(os.path.dirname(
  19. os.path.abspath(__file__)), '..'))
  20. import pagure
  21. import pagure.lib
  22. import tests
  23. from pagure.lib.repo import PagureRepo
  24. class PagureFlaskRoadmaptests(tests.Modeltests):
  25. """ Tests for the pagure's roadmap """
  26. @patch('pagure.lib.git.update_git')
  27. @patch('pagure.lib.notify.send_email')
  28. def test_ticket_with_no_roadmap(self, p_send_email, p_ugt):
  29. """ Test creating a ticket without roadmap. """
  30. p_send_email.return_value = True
  31. p_ugt.return_value = True
  32. tests.create_projects(self.session)
  33. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  34. user = tests.FakeUser()
  35. user.username = 'pingou'
  36. with tests.user_set(self.app.application, user):
  37. # Get the CSRF token
  38. output = self.app.get('/test/new_issue')
  39. self.assertEqual(output.status_code, 200)
  40. self.assertTrue(
  41. u'<div class="card-header">\n New issue'
  42. in output.data)
  43. csrf_token = output.data.split(
  44. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  45. data = {
  46. 'title': 'Test issue',
  47. 'issue_content': 'We really should improve on this issue',
  48. 'status': 'Open',
  49. 'csrf_token': csrf_token,
  50. }
  51. # Create the issue
  52. output = self.app.post(
  53. '/test/new_issue', data=data, follow_redirects=True)
  54. self.assertEqual(output.status_code, 200)
  55. self.assertIn(
  56. u'<title>Issue #1: Test issue - test - Pagure</title>',
  57. output.data)
  58. self.assertIn(
  59. u'<a class="btn btn-primary btn-sm" '
  60. 'href="/test/issue/1/edit" title="Edit this issue">',
  61. output.data)
  62. @patch('pagure.lib.git.update_git')
  63. @patch('pagure.lib.notify.send_email')
  64. def test_ticket_with_roadmap(self, p_send_email, p_ugt):
  65. """ Test creating a ticket with roadmap. """
  66. p_send_email.return_value = True
  67. p_ugt.return_value = True
  68. tests.create_projects(self.session)
  69. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  70. # Set some milestone
  71. repo = pagure.lib.get_authorized_project(self.session, 'test')
  72. repo.milestone = {'v1.0': '', 'v2.0': 'Tomorrow!'}
  73. self.session.add(repo)
  74. self.session.commit()
  75. user = tests.FakeUser()
  76. user.username = 'pingou'
  77. with tests.user_set(self.app.application, user):
  78. # Get the CSRF token
  79. output = self.app.get('/test/new_issue')
  80. self.assertEqual(output.status_code, 200)
  81. self.assertTrue(
  82. u'<div class="card-header">\n New issue'
  83. in output.data)
  84. csrf_token = output.data.split(
  85. u'name="csrf_token" type="hidden" value="')[1].split(u'">')[0]
  86. data = {
  87. 'title': 'Test issue',
  88. 'issue_content': 'We really should improve on this issue',
  89. 'status': 'Open',
  90. 'csrf_token': csrf_token,
  91. }
  92. # Create the issue
  93. output = self.app.post(
  94. '/test/new_issue', data=data, follow_redirects=True)
  95. self.assertEqual(output.status_code, 200)
  96. self.assertIn(
  97. u'<title>Issue #1: Test issue - test - Pagure</title>',
  98. output.data)
  99. self.assertIn(
  100. u'<a class="btn btn-primary btn-sm" '
  101. 'href="/test/issue/1/edit" title="Edit this issue">',
  102. output.data)
  103. # Mark the ticket for the roadmap
  104. data = {
  105. 'tag': 'roadmap',
  106. 'csrf_token': csrf_token,
  107. }
  108. output = self.app.post(
  109. '/test/issue/1/update', data=data, follow_redirects=True)
  110. self.assertEqual(output.status_code, 200)
  111. self.assertIn(
  112. u'<title>Issue #1: Test issue - test - Pagure</title>',
  113. output.data)
  114. self.assertIn(
  115. u'<a class="btn btn-primary btn-sm" '
  116. 'href="/test/issue/1/edit" title="Edit this issue">',
  117. output.data)
  118. def test_update_milestones(self):
  119. """ Test updating milestones of a repo. """
  120. tests.create_projects(self.session)
  121. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  122. # Set some milestones
  123. repo = pagure.lib.get_authorized_project(self.session, 'test')
  124. self.assertEqual(repo.milestones, {})
  125. user = tests.FakeUser()
  126. user.username = 'pingou'
  127. with tests.user_set(self.app.application, user):
  128. # Get the CSRF token
  129. output = self.app.get('/test/settings')
  130. self.assertEqual(output.status_code, 200)
  131. self.assertIn(
  132. u'<title>Settings - test - Pagure</title>', output.data)
  133. self.assertIn(u'<h3>Settings for test</h3>', output.data)
  134. csrf_token = output.data.split(
  135. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  136. data = {
  137. 'milestones': 1,
  138. 'milestone_dates': 'Tomorrow',
  139. }
  140. output = self.app.post(
  141. '/test/update/milestones', data=data, follow_redirects=True)
  142. self.assertEqual(output.status_code, 200)
  143. # Check the redirect
  144. self.assertIn(
  145. u'<title>Settings - test - Pagure</title>', output.data)
  146. self.assertIn('<h3>Settings for test</h3>', output.data)
  147. # Check the result of the action -- None, no CSRF
  148. repo = pagure.lib.get_authorized_project(self.session, 'test')
  149. self.assertEqual(repo.milestones, {})
  150. data = {
  151. 'milestones': 1,
  152. 'milestone_dates': 'Tomorrow',
  153. 'csrf_token': csrf_token,
  154. }
  155. output = self.app.post(
  156. '/test/update/milestones', data=data, follow_redirects=True)
  157. self.assertEqual(output.status_code, 200)
  158. # Check the redirect
  159. self.assertIn(
  160. u'<title>Settings - test - Pagure</title>', output.data)
  161. self.assertIn(u'<h3>Settings for test</h3>', output.data)
  162. self.assertIn(u'Milestones updated', output.data)
  163. # Check the result of the action -- Milestones recorded
  164. self.session.commit()
  165. repo = pagure.lib.get_authorized_project(self.session, 'test')
  166. self.assertEqual(repo.milestones, {u'1': {u'active': False, u'date': None}})
  167. data = {
  168. 'milestones': ['v1.0', 'v2.0'],
  169. 'milestone_dates_1': 'Tomorrow',
  170. 'milestone_dates_2': '',
  171. 'csrf_token': csrf_token,
  172. }
  173. output = self.app.post(
  174. '/test/update/milestones', data=data, follow_redirects=True)
  175. self.assertEqual(output.status_code, 200)
  176. # Check the redirect
  177. self.assertIn(
  178. u'<title>Settings - test - Pagure</title>', output.data)
  179. self.assertIn(u'<h3>Settings for test</h3>', output.data)
  180. self.assertIn(u'Milestones updated', output.data)
  181. # Check the result of the action -- Milestones recorded
  182. self.session.commit()
  183. repo = pagure.lib.get_authorized_project(self.session, 'test')
  184. self.assertEqual(
  185. repo.milestones,
  186. {
  187. u'v1.0': {u'active': False, u'date': None},
  188. u'v2.0': {u'active': False, u'date': None}
  189. }
  190. )
  191. # Check error - less milestones than dates
  192. data = {
  193. 'milestones': ['v1.0', 'v2.0'],
  194. 'milestone_date_1': 'Tomorrow',
  195. 'milestone_date_2': 'Next week',
  196. 'milestone_date_3': 'Next Year',
  197. 'csrf_token': csrf_token,
  198. }
  199. output = self.app.post(
  200. '/test/update/milestones', data=data, follow_redirects=True)
  201. self.assertEqual(output.status_code, 200)
  202. # Check the redirect
  203. self.assertIn(
  204. u'<title>Settings - test - Pagure</title>', output.data)
  205. self.assertIn(u'<h3>Settings for test</h3>', output.data)
  206. # Check the result of the action -- Milestones un-changed
  207. self.session.commit()
  208. repo = pagure.lib.get_authorized_project(self.session, 'test')
  209. self.assertEqual(
  210. repo.milestones,
  211. {
  212. u'v1.0': {u'active': False, u'date': u'Tomorrow'},
  213. u'v2.0': {u'active': False, u'date': u'Next week'}
  214. }
  215. )
  216. # Check error - Twice the same milestone
  217. data = {
  218. 'milestones': ['v1.0', 'v2.0', 'v2.0'],
  219. 'milestone_date_1': 'Tomorrow',
  220. 'milestone_date_2': 'Next week',
  221. 'milestone_date_3': 'Next Year',
  222. 'csrf_token': csrf_token,
  223. }
  224. output = self.app.post(
  225. '/test/update/milestones', data=data, follow_redirects=True)
  226. self.assertEqual(output.status_code, 200)
  227. # Check the redirect
  228. self.assertIn(
  229. u'<title>Settings - test - Pagure</title>', output.data)
  230. self.assertIn(u'<h3>Settings for test</h3>', output.data)
  231. self.assertIn(
  232. u'</button>\n'
  233. ' Milestone v2.0 is present 2 times',
  234. output.data)
  235. # Check the result of the action -- Milestones un-changed
  236. self.session.commit()
  237. repo = pagure.lib.get_authorized_project(self.session, 'test')
  238. self.assertEqual(
  239. repo.milestones,
  240. {
  241. u'v1.0': {u'active': False, u'date': u'Tomorrow'},
  242. u'v2.0': {u'active': False, u'date': u'Next week'}
  243. }
  244. )
  245. # Check error - Twice the same date
  246. data = {
  247. 'milestones': ['v1.0', 'v2.0', 'v3.0'],
  248. 'milestone_date_1': 'Tomorrow',
  249. 'milestone_date_2': 'Next week',
  250. 'milestone_date_3': 'Next week',
  251. 'csrf_token': csrf_token,
  252. }
  253. output = self.app.post(
  254. '/test/update/milestones', data=data, follow_redirects=True)
  255. self.assertEqual(output.status_code, 200)
  256. # Check the redirect
  257. self.assertIn(
  258. u'<title>Settings - test - Pagure</title>', output.data)
  259. self.assertIn(u'<h3>Settings for test</h3>', output.data)
  260. self.assertIn(
  261. u'</button>\n'
  262. ' Milestones updated',
  263. output.data)
  264. # Check the result of the action -- Milestones updated
  265. self.session.commit()
  266. repo = pagure.lib.get_authorized_project(self.session, 'test')
  267. self.assertEqual(
  268. repo.milestones,
  269. {
  270. u'v1.0': {u'active': False, u'date': u'Tomorrow'},
  271. u'v2.0': {u'active': False, u'date': u'Next week'},
  272. u'v3.0': {u'active': False, u'date': u'Next week'},
  273. }
  274. )
  275. # Check for an invalid project
  276. output = self.app.post(
  277. '/foo/update/milestones', data=data)
  278. self.assertEqual(output.status_code, 404)
  279. # Check the behavior if the project disabled the issue tracker
  280. settings = repo.settings
  281. settings['issue_tracker'] = False
  282. repo.settings = settings
  283. self.session.add(repo)
  284. self.session.commit()
  285. output = self.app.post(
  286. '/test/update/milestones', data=data)
  287. self.assertEqual(output.status_code, 404)
  288. # Check for a non-admin user
  289. settings = repo.settings
  290. settings['issue_tracker'] = True
  291. repo.settings = settings
  292. self.session.add(repo)
  293. self.session.commit()
  294. user.username = 'ralph'
  295. with tests.user_set(self.app.application, user):
  296. output = self.app.post(
  297. '/test/update/milestones', data=data)
  298. self.assertEqual(output.status_code, 403)
  299. @patch('pagure.lib.git.update_git')
  300. @patch('pagure.lib.notify.send_email')
  301. def test_milestones_without_dates(self, p_send_email, p_ugt):
  302. """ Test creating two milestones with no dates. """
  303. tests.create_projects(self.session)
  304. tests.create_projects_git(os.path.join(self.path, 'repos'), bare=True)
  305. user = tests.FakeUser()
  306. user.username = 'pingou'
  307. with tests.user_set(self.app.application, user):
  308. # Get the CSRF token
  309. output = self.app.get('/test/settings')
  310. csrf_token = output.data.split(
  311. 'name="csrf_token" type="hidden" value="')[1].split('">')[0]
  312. data = {
  313. 'milestones': ['v1.0', 'v2.0'],
  314. 'milestone_dates': ['', ''],
  315. 'csrf_token': csrf_token,
  316. }
  317. output = self.app.post(
  318. '/test/update/milestones', data=data, follow_redirects=True)
  319. self.assertEqual(output.status_code, 200)
  320. # Check the redirect
  321. self.assertIn(
  322. u'<title>Settings - test - Pagure</title>', output.data)
  323. self.assertIn(u'<h3>Settings for test</h3>', output.data)
  324. self.assertIn(u'Milestones updated', output.data)
  325. # Check the result of the action -- Milestones recorded
  326. self.session.commit()
  327. repo = pagure.lib.get_authorized_project(self.session, 'test')
  328. self.assertEqual(
  329. repo.milestones,
  330. {
  331. u'v1.0': {u'active': False, u'date': None},
  332. u'v2.0': {u'active': False, u'date': None}
  333. }
  334. )
  335. @patch('pagure.lib.git.update_git')
  336. @patch('pagure.lib.notify.send_email')
  337. def test_roadmap_ui(self, p_send_email, p_ugt):
  338. """ Test viewing the roadmap of a repo. """
  339. p_send_email.return_value = True
  340. p_ugt.return_value = True
  341. self.test_update_milestones()
  342. user = tests.FakeUser()
  343. user.username = 'pingou'
  344. with tests.user_set(self.app.application, user):
  345. # Get the CSRF token
  346. output = self.app.get('/test/new_issue')
  347. self.assertEqual(output.status_code, 200)
  348. self.assertTrue(
  349. u'<div class="card-header">\n New issue'
  350. in output.data)
  351. csrf_token = output.data.split(
  352. u'name="csrf_token" type="hidden" value="')[1].split(u'">')[0]
  353. # Create an unplanned milestone
  354. data = {
  355. 'milestones': ['v1.0', 'v2.0', 'unplanned'],
  356. 'milestone_date_1': 'Tomorrow',
  357. 'milestone_date_2': '',
  358. 'milestone_date_3': '',
  359. 'active_milestone_1': True,
  360. 'active_milestone_2': True,
  361. 'active_milestone_3': True,
  362. 'csrf_token': csrf_token,
  363. }
  364. output = self.app.post(
  365. '/test/update/milestones', data=data, follow_redirects=True)
  366. self.assertEqual(output.status_code, 200)
  367. # Check the redirect
  368. self.assertIn(
  369. u'<title>Settings - test - Pagure</title>', output.data)
  370. self.assertIn(u'<h3>Settings for test</h3>', output.data)
  371. self.assertIn(u'Milestones updated', output.data)
  372. # Check the result of the action -- Milestones recorded
  373. self.session.commit()
  374. repo = pagure.lib._get_project(self.session, 'test')
  375. self.assertEqual(
  376. repo.milestones,
  377. {
  378. u'unplanned': {u'active': True, u'date': None},
  379. u'v1.0': {u'active': True, u'date': u'Tomorrow'},
  380. u'v2.0': {u'active': True, u'date': None}
  381. }
  382. )
  383. # Create the issues
  384. for cnt in range(6):
  385. cnt += 1
  386. data = {
  387. 'title': 'Test issue %s' % cnt,
  388. 'issue_content': 'We really should improve on this '
  389. 'issue %s' % cnt,
  390. 'csrf_token': csrf_token,
  391. }
  392. output = self.app.post(
  393. '/test/new_issue', data=data, follow_redirects=True)
  394. self.assertEqual(output.status_code, 200)
  395. self.assertIn(
  396. u'<title>Issue #{0}: Test issue {0} - test - '
  397. 'Pagure</title>'.format(cnt),
  398. output.data)
  399. self.assertIn(
  400. u'<a class="btn btn-primary btn-sm" '
  401. 'href="/test/issue/%s/edit" title="Edit this '
  402. 'issue">' % cnt,
  403. output.data)
  404. # Mark the ticket for the roadmap
  405. mstone = 'v%s.0' % cnt
  406. if cnt >= 3:
  407. if (cnt % 3) == 0:
  408. mstone = 'unplanned'
  409. else:
  410. mstone = 'v%s.0' % (cnt % 3)
  411. data = {
  412. 'milestone': mstone,
  413. 'csrf_token': csrf_token,
  414. }
  415. output = self.app.post(
  416. '/test/issue/%s/update' % cnt, data=data,
  417. follow_redirects=True)
  418. self.assertEqual(output.status_code, 200)
  419. self.assertIn(
  420. u'<title>Issue #{0}: Test issue {0} - test - '
  421. 'Pagure</title>'.format(cnt),
  422. output.data)
  423. self.assertIn(
  424. u'<a class="btn btn-primary btn-sm" '
  425. 'href="/test/issue/%s/edit" title="Edit this '
  426. 'issue">' % cnt,
  427. output.data)
  428. self.assertIn(
  429. u'</button>\n '
  430. u'Issue set to the milestone: %s\n' % mstone,
  431. output.data)
  432. repo = pagure.lib.get_authorized_project(self.session, 'test')
  433. # Mark ticket #1 as Fixed
  434. for iid in [1, 4]:
  435. ticket = pagure.lib.search_issues(
  436. self.session,
  437. repo,
  438. issueid=iid
  439. )
  440. ticket.status = 'Closed'
  441. ticket.close_status = 'Fixed'
  442. self.session.add(ticket)
  443. self.session.commit()
  444. # test the roadmap view
  445. output = self.app.get('/test/roadmap')
  446. self.assertEqual(output.status_code, 200)
  447. self.assertIn(u'<th>v2.0', output.data)
  448. self.assertIn(u'<th>unplanned', output.data)
  449. self.assertEqual(
  450. output.data.count(u'<span class="label label-default">#'), 4)
  451. # test the roadmap view for all milestones
  452. output = self.app.get('/test/roadmap?all_stones=True&status=All')
  453. self.assertEqual(output.status_code, 200)
  454. self.assertIn(u'<th>v1.0', output.data)
  455. self.assertIn(u'<th>v2.0', output.data)
  456. self.assertIn(u'<th>unplanned', output.data)
  457. self.assertEqual(
  458. output.data.count(u'<span class="label label-default">#'), 6)
  459. # test the roadmap view for a specific milestone
  460. output = self.app.get('/test/roadmap?milestone=v2.0')
  461. self.assertEqual(output.status_code, 200)
  462. self.assertIn(u'<th>v2.0', output.data)
  463. self.assertEqual(
  464. output.data.count(u'<span class="label label-default">#'), 2)
  465. # test the roadmap view for a specific milestone - open
  466. output = self.app.get('/test/roadmap?milestone=v1.0')
  467. self.assertEqual(output.status_code, 200)
  468. self.assertIn(u'No issues found', output.data)
  469. self.assertEqual(
  470. output.data.count(u'<span class="label label-default">#'), 0)
  471. # test the roadmap view for a specific milestone - closed
  472. output = self.app.get(
  473. '/test/roadmap?milestone=v1.0&status=All&all_stones=True')
  474. self.assertEqual(output.status_code, 200)
  475. self.assertIn(u'<th>v1.0', output.data)
  476. self.assertEqual(
  477. output.data.count(u'<span class="label label-default">#'), 2)
  478. # test the roadmap view for a specific tag
  479. output = self.app.get('/test/roadmap?milestone=v2.0&tag=unknown')
  480. self.assertEqual(output.status_code, 200)
  481. self.assertIn(u'No issues found', output.data)
  482. self.assertEqual(
  483. output.data.count(u'<span class="label label-default">#'), 0)
  484. # test the roadmap view for errors
  485. output = self.app.get('/foo/roadmap')
  486. self.assertEqual(output.status_code, 404)
  487. repo = pagure.lib.get_authorized_project(self.session, 'test')
  488. settings = repo.settings
  489. settings['issue_tracker'] = False
  490. repo.settings = settings
  491. self.session.add(repo)
  492. self.session.commit()
  493. output = self.app.get('/test/roadmap', data=data)
  494. self.assertEqual(output.status_code, 404)
  495. if __name__ == '__main__':
  496. unittest.main(verbosity=2)