test_pagure_flask_ui_roadmap.py 21 KB

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