test_pagure_flask_ui_roadmap.py 23 KB

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