From d86db98e887e7526706dd55cf26096540254f268 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 1/15] Improve tests to include a close_status


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_api_issue_change_status.py b/tests/test_pagure_flask_api_issue_change_status.py
index 20712c5..e6bd732 100644
--- a/tests/test_pagure_flask_api_issue_change_status.py
+++ b/tests/test_pagure_flask_api_issue_change_status.py
@@ -29,6 +29,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(
 
 import pagure
 import pagure.lib
+import pagure.lib.model
 import tests
 
 
@@ -205,6 +206,7 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
         issue = pagure.lib.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
+
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
     def test_api_change_status_issue(self):
         """ Test the api_change_status_issue method of the flask api. """
@@ -241,6 +243,38 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
         self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error'])
 
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
+    def test_api_change_status_issue_closed_status(self):
+        """ Test the api_change_status_issue method of the flask api. """
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        close_status = repo.close_status
+        close_status = ['Fixed', 'Upstream', 'Invalid']
+        repo.close_status = close_status
+        self.session.add(repo)
+        self.session.commit()
+
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+
+        data = {
+            'status': 'Closed',
+            'close_status': 'Fixed'
+        }
+
+        # Valid request
+        output = self.app.post(
+            '/api/0/test/issue/1/status', data=data, headers=headers)
+        self.assertEqual(output.status_code, 200)
+        data = json.loads(output.get_data(as_text=True))
+
+        self.assertDictEqual(
+            data,
+            {'message':[
+                'Issue status updated to: Closed (was: Open)',
+                'Issue close_status updated to: Fixed'
+            ]}
+        )
+
+    @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
     def test_api_change_status_issue_no_ticket_project_less(self):
         """ Test the api_change_status_issue method of the flask api. """
 

From 9a16eb6fe553a9a98632999eef9cf073aa581160 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 2/15] Add test when api_change_status raises an exception


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_api_issue_change_status.py b/tests/test_pagure_flask_api_issue_change_status.py
index e6bd732..1a4542a 100644
--- a/tests/test_pagure_flask_api_issue_change_status.py
+++ b/tests/test_pagure_flask_api_issue_change_status.py
@@ -206,6 +206,37 @@ class PagureFlaskApiIssueChangeStatustests(tests.Modeltests):
         issue = pagure.lib.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.status, 'Open')
 
+    @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
+    @patch(
+        'pagure.lib.edit_issue',
+        MagicMock(side_effect=pagure.exceptions.PagureException('error')))
+    def test_api_change_status_issue_raise_error(self):
+        """ Test the api_change_status_issue method of the flask api. """
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        close_status = repo.close_status
+        close_status = ['Fixed', 'Upstream', 'Invalid']
+        repo.close_status = close_status
+        self.session.add(repo)
+        self.session.commit()
+
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+
+        data = {
+            'status': 'Closed',
+            'close_status': 'Fixed'
+        }
+
+        # Valid request
+        output = self.app.post(
+            '/api/0/test/issue/1/status', data=data, headers=headers)
+        self.assertEqual(output.status_code, 400)
+        data = json.loads(output.get_data(as_text=True))
+
+        self.assertDictEqual(
+            data,
+            {u'error': u'error', u'error_code': u'ENOCODE'}
+        )
 
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
     def test_api_change_status_issue(self):

From d00a9e8f5112cc892acf9796ffd818e1112aaae7 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 3/15] Simplify code checking for a milestone


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/pagure/api/issue.py b/pagure/api/issue.py
index 49a239b..7a11a89 100644
--- a/pagure/api/issue.py
+++ b/pagure/api/issue.py
@@ -878,9 +878,7 @@ def api_change_milestone_issue(repo, issueid, username=None, namespace=None):
         csrf_enabled=False)
 
     if form.validate_on_submit():
-        new_milestone = form.milestone.data
-        if new_milestone == '':
-            new_milestone = None  # unset milestone
+        new_milestone = form.milestone.data or None
         try:
             # Update status
             message = pagure.lib.edit_issue(

From 0bc20d93f3610dcb06d575b8b59e78227f050f20 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 4/15] Restructure the tests for the api_change_milestone endpoint


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_api_issue.py b/tests/test_pagure_flask_api_issue.py
index 4efc4f2..a32a8b7 100644
--- a/tests/test_pagure_flask_api_issue.py
+++ b/tests/test_pagure_flask_api_issue.py
@@ -2265,7 +2265,7 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             }
         )
 
-    def test_api_change_milestone_issue(self):
+    def test_api_change_milestone_issue_invalid_project(self):
         """ Test the api_change_milestone_issue method of the flask api. """
         tests.create_projects(self.session)
         tests.create_projects_git(os.path.join(self.path, 'tickets'))
@@ -2292,6 +2292,21 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             }
         )
 
+    def test_api_change_milestone_issue_wrong_token(self):
+        """ Test the api_change_milestone_issue method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        # Set some milestones to the project
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
+        self.session.add(repo)
+        self.session.commit()
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+
         # Valid token, wrong project
         output = self.app.post('/api/0/test2/issue/1/milestone', headers=headers)
         self.assertEqual(output.status_code, 401)
@@ -2302,6 +2317,21 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(
             pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
 
+    def test_api_change_milestone_issue_no_issue(self):
+        """ Test the api_change_milestone_issue method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        # Set some milestones to the project
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
+        self.session.add(repo)
+        self.session.commit()
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+
         # No issue
         output = self.app.post('/api/0/test/issue/1/milestone', headers=headers)
         self.assertEqual(output.status_code, 404)
@@ -2314,6 +2344,20 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             }
         )
 
+    def test_api_change_milestone_issue_no_milestone(self):
+        """ Test the api_change_milestone_issue method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        # Set some milestones to the project
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
+        self.session.add(repo)
+        self.session.commit()
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
         # Create normal issue
         repo = pagure.lib.get_authorized_project(self.session, 'test')
         msg = pagure.lib.new_issue(
@@ -2352,6 +2396,39 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         issue = pagure.lib.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
+    def test_api_change_milestone_issue_invalid_milestone(self):
+        """ Test the api_change_milestone_issue method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        # Set some milestones to the project
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
+        self.session.add(repo)
+        self.session.commit()
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+        # Create normal issue
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue #1',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=False,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue #1')
+
+        # Check milestone before
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        self.assertEqual(issue.milestone, None)
+
         data = {
             'milestone': 'milestone-1-0',
         }
@@ -2374,6 +2451,90 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
             }
         )
 
+    def test_api_change_milestone_issue(self):
+        """ Test the api_change_milestone_issue method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        # Set some milestones to the project
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
+        self.session.add(repo)
+        self.session.commit()
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+        # Create normal issue
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue #1',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=False,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue #1')
+
+        # Check milestone before
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        self.assertEqual(issue.milestone, None)
+
+        data = {
+            'milestone': 'v1.0',
+        }
+
+        # Valid requests
+        output = self.app.post(
+            '/api/0/test/issue/1/milestone', data=data, headers=headers)
+        self.assertEqual(output.status_code, 200)
+        data = json.loads(output.get_data(as_text=True))
+        self.assertDictEqual(
+            data,
+            {
+                "message": [
+                    "Issue set to the milestone: v1.0"
+                ]
+            }
+        )
+
+    def test_api_change_milestone_issue_remove_milestone(self):
+        """ Test the api_change_milestone_issue method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        # Set some milestones to the project
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
+        self.session.add(repo)
+        self.session.commit()
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+        # Create normal issue
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue #1',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=False,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue #1')
+
+        # Check milestone before
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        self.assertEqual(issue.milestone, None)
+
         data = {
             'milestone': 'v1.0',
         }
@@ -2416,6 +2577,39 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         issue = pagure.lib.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
+    def test_api_change_milestone_issue_remove_milestone2(self):
+        """ Test the api_change_milestone_issue method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        # Set some milestones to the project
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
+        self.session.add(repo)
+        self.session.commit()
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+        # Create normal issue
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue #1',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=False,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue #1')
+
+        # Check milestone before
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        issue = pagure.lib.search_issues(self.session, repo, issueid=1)
+        self.assertEqual(issue.milestone, None)
+
         data = {
             'milestone': 'v1.0',
         }
@@ -2456,11 +2650,40 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         issue = pagure.lib.search_issues(self.session, repo, issueid=1)
         self.assertEqual(issue.milestone, None)
 
+    def test_api_change_milestone_issue_unauthorized(self):
+        """ Test the api_change_milestone_issue method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        # Set some milestones to the project
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
+        self.session.add(repo)
+        self.session.commit()
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+        # Create normal issue
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue #1',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=False,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue #1')
+
         headers = {'Authorization': 'token pingou_foo'}
+        data = {'milestone': 'v1.0',}
 
         # Un-authorized issue
         output = self.app.post(
-            '/api/0/foo/issue/1/milestone', data=data, headers=headers)
+            '/api/0/foo/issue/1/milestone', data={}, headers=headers)
         self.assertEqual(output.status_code, 401)
         data = json.loads(output.get_data(as_text=True))
         self.assertEqual(sorted(data.keys()), ['error', 'error_code'])

From 51514cf5f64ce0d7a8b5c83b72aec98bb69bcc7d Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 5/15] Add more tests for the api_change_milestone_issue API method


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_api_issue.py b/tests/test_pagure_flask_api_issue.py
index a32a8b7..f5ee7d0 100644
--- a/tests/test_pagure_flask_api_issue.py
+++ b/tests/test_pagure_flask_api_issue.py
@@ -2692,6 +2692,52 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         self.assertEqual(
             pagure.api.APIERROR.EINVALIDTOK.name, data['error_code'])
 
+    @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
+    @patch(
+        'pagure.lib.add_metadata_update_notif',
+        MagicMock(side_effect=pagure.exceptions.PagureException('error')))
+    def test_api_change_milestone_issue_raises_exception(self):
+        """ Test the api_change_milestone_issue method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        # Set some milestones to the project
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        repo.milestones = {'v1.0': None, 'v2.0': 'Soon'}
+        self.session.add(repo)
+        self.session.commit()
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+        # Create normal issue
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue #1',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=False,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue #1')
+
+        data = {
+            'milestone': 'v1.0',
+        }
+
+        # Valid requests
+        output = self.app.post(
+            '/api/0/test/issue/1/milestone', data=data, headers=headers)
+        self.assertEqual(output.status_code, 400)
+        data = json.loads(output.get_data(as_text=True))
+        self.assertDictEqual(
+            data,
+            {u'error': u'error', u'error_code': u'ENOCODE'}
+        )
+
     @patch('pagure.lib.git.update_git')
     @patch('pagure.lib.notify.send_email')
     def test_api_view_issue_comment(self, p_send_email, p_ugt):

From ce02c2b3c3c354d9f972166f6eddcadba6089134 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 6/15] Add tests for the no new branch hook


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_ui_plugins_pagure_no_new_branch.py b/tests/test_pagure_flask_ui_plugins_pagure_no_new_branch.py
new file mode 100644
index 0000000..9c594bb
--- /dev/null
+++ b/tests/test_pagure_flask_ui_plugins_pagure_no_new_branch.py
@@ -0,0 +1,192 @@
+# -*- coding: utf-8 -*-
+
+"""
+ (c) 2015-2018 - Copyright Red Hat Inc
+
+ Authors:
+   Pierre-Yves Chibon <pingou@pingoured.fr>
+
+"""
+
+from __future__ import unicode_literals
+
+__requires__ = ['SQLAlchemy >= 0.8']
+
+import unittest
+import shutil
+import sys
+import os
+
+
+sys.path.insert(0, os.path.join(os.path.dirname(
+    os.path.abspath(__file__)), '..'))
+
+import pagure.lib
+import tests
+
+
+class PagureFlaskPluginPagureNoNewBranchHooktests(tests.SimplePagureTest):
+    """ Tests for pagure_no_new_branches plugin of pagure """
+
+    def setUp(self):
+        """ Set up the environnment, ran before every tests. """
+        super(PagureFlaskPluginPagureNoNewBranchHooktests, self).setUp()
+
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'repos'))
+
+        pagure.config.config['GIT_FOLDER'] = os.path.join(
+            self.path, 'repos')
+
+        with tests.user_set(self.app.application, tests.FakeUser()):
+            self.csrf_token = self.get_csrf()
+
+    def test_plugin_pagure_ticket_no_data(self):
+        """ Test the pagure_ticket plugin on/off endpoint. """
+
+        user = tests.FakeUser(username='pingou')
+        with tests.user_set(self.app.application, user):
+            output = self.app.get(
+                '/test/settings/Prevent creating new branches by git push')
+            self.assertEqual(output.status_code, 200)
+            output_text = output.get_data(as_text=True)
+            self.assertIn(
+                '<title>Settings Prevent creating new branches by git '
+                'push - test - Pagure</title>', output_text)
+            self.assertIn(
+                '<input class="form-control" id="active" name="active" '
+                'type="checkbox" value="y">', output_text)
+
+            data = {}
+
+            output = self.app.post(
+                '/test/settings/Prevent creating new branches by git push',
+                data=data)
+            self.assertEqual(output.status_code, 200)
+            output_text = output.get_data(as_text=True)
+            self.assertIn(
+                '<title>Settings Prevent creating new branches by git push '
+                '- test - Pagure</title>', output_text)
+            self.assertIn(
+                '<input class="form-control" id="active" name="active" '
+                'type="checkbox" value="y">', output_text)
+
+    def test_plugin_pagure_ticket_deactivate(self):
+        """ Test the pagure_ticket plugin on/off endpoint. """
+        user = tests.FakeUser(username='pingou')
+        with tests.user_set(self.app.application, user):
+            data = {'csrf_token': self.csrf_token}
+
+            output = self.app.post(
+                '/test/settings/Prevent creating new branches by git push',
+                data=data, follow_redirects=True)
+            self.assertEqual(output.status_code, 200)
+            output_text = output.get_data(as_text=True)
+            self.assertIn(
+                '<h5 class="pl-2 font-weight-bold text-muted">'
+                'Project Settings</h5>\n', output_text)
+            self.assertIn(
+                'Hook Prevent creating new branches by git push deactivated',
+                output_text)
+
+            output = self.app.get(
+                '/test/settings/Prevent creating new branches by git push')
+            self.assertEqual(output.status_code, 200)
+            output_text = output.get_data(as_text=True)
+            self.assertIn(
+                '<title>Settings Prevent creating new branches by git push '
+                '- test - Pagure</title>', output_text)
+            self.assertIn(
+                '<input class="form-control" id="active" name="active" '
+                'type="checkbox" value="y">', output_text)
+
+            self.assertFalse(os.path.exists(os.path.join(
+                self.path, 'repos', 'test.git', 'hooks', 'post-receive.pagure')))
+
+    def test_plugin_pagure_ticket_activate(self):
+        """ Test the pagure_ticket plugin on/off endpoint. """
+
+        user = tests.FakeUser(username='pingou')
+        with tests.user_set(self.app.application, user):
+            # Activate hook
+            data = {
+                'csrf_token': self.csrf_token,
+                'active': 'y',
+            }
+
+            output = self.app.post(
+                '/test/settings/Prevent creating new branches by git push',
+                data=data, follow_redirects=True)
+            self.assertEqual(output.status_code, 200)
+            output_text = output.get_data(as_text=True)
+            self.assertIn(
+                '<h5 class="pl-2 font-weight-bold text-muted">'
+                'Project Settings</h5>\n', output_text)
+            self.assertIn(
+                'Hook Prevent creating new branches by git push activated',
+                output_text)
+
+            output = self.app.get(
+                '/test/settings/Prevent creating new branches by git push')
+            self.assertEqual(output.status_code, 200)
+            output_text = output.get_data(as_text=True)
+            self.assertIn(
+                '<title>Settings Prevent creating new branches by git push '
+                '- test - Pagure</title>', output_text)
+            self.assertIn(
+                '<input checked class="form-control" id="active" name="active" '
+                'type="checkbox" value="y">', output_text)
+
+            self.assertTrue(os.path.exists(os.path.join(
+                self.path, 'repos', 'test.git', 'hooks',
+                'pre-receive.pagure_no_new_branches')))
+
+            # De-Activate hook
+            data = {'csrf_token': self.csrf_token}
+            output = self.app.post(
+                '/test/settings/Prevent creating new branches by git push',
+                data=data, follow_redirects=True)
+            self.assertEqual(output.status_code, 200)
+            output_text = output.get_data(as_text=True)
+            self.assertIn(
+                '<h5 class="pl-2 font-weight-bold text-muted">'
+                'Project Settings</h5>\n', output_text)
+            self.assertIn(
+                'Hook Prevent creating new branches by git push deactivated',
+                output_text)
+
+            output = self.app.get(
+                '/test/settings/Prevent creating new branches by git push')
+            self.assertEqual(output.status_code, 200)
+            output_text = output.get_data(as_text=True)
+            self.assertIn(
+                '<title>Settings Prevent creating new branches by git push '
+                '- test - Pagure</title>', output_text)
+            self.assertIn(
+                '<input class="form-control" id="active" name="active" '
+                'type="checkbox" value="y">', output_text)
+
+            self.assertFalse(os.path.exists(os.path.join(
+                self.path, 'repos', 'test.git', 'hooks',
+                'pre-receive.pagure_no_new_branches')))
+
+    def test_plugin_pagure_ticket_activate_w_no_repo(self):
+        """ Test the pagure_ticket plugin on/off endpoint. """
+        shutil.rmtree(os.path.join(self.path, 'repos', 'test.git'))
+
+        user = tests.FakeUser(username='pingou')
+        with tests.user_set(self.app.application, user):
+            # Try re-activate hook w/o the git repo
+            data = {
+                'csrf_token': self.csrf_token,
+                'active': 'y',
+            }
+
+            output = self.app.post(
+                '/test/settings/Prevent creating new branches by git push',
+                data=data)
+            self.assertEqual(output.status_code, 404)
+
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)

From 1d97e085d56882365c36e7f1205c2ae8aa4cff66 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 7/15] Expand the tests for the default hook


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_ui_plugins_default_hook.py b/tests/test_pagure_flask_ui_plugins_default_hook.py
index 32c2b93..5993265 100644
--- a/tests/test_pagure_flask_ui_plugins_default_hook.py
+++ b/tests/test_pagure_flask_ui_plugins_default_hook.py
@@ -19,8 +19,9 @@ import shutil
 import sys
 import os
 
+import flask
 import pygit2
-from mock import patch
+from mock import patch, MagicMock
 
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
@@ -76,6 +77,84 @@ class PagureFlaskPluginDefaultHooktests(tests.Modeltests):
         self.assertTrue(os.path.exists(os.path.join(
             self.path, 'repos', 'test.git', 'hooks', 'post-receive')))
 
+    def test_plugin_default_remove(self):
+        """ Check that the default plugin can be correctly removed if
+        somehow managed.
+        """
+
+        task = pagure.lib.new_project(
+            self.session,
+            user='pingou',
+            name='test',
+            blacklist=[],
+            allowed_prefix=[],
+            gitfolder=os.path.join(self.path, 'repos'),
+            docfolder=os.path.join(self.path, 'docs'),
+            ticketfolder=os.path.join(self.path, 'tickets'),
+            requestfolder=os.path.join(self.path, 'requests'),
+            description=None,
+            url=None, avatar_email=None,
+            parent_id=None,
+            add_readme=False,
+            userobj=None,
+            prevent_40_chars=False,
+            namespace=None
+        )
+        self.assertEqual(task.get(),
+                         {'endpoint': 'ui_ns.view_repo',
+                          'repo': 'test',
+                          'namespace': None})
+
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        plugin = pagure.lib.plugins.get_plugin('default')
+        dbobj = plugin.db_object()
+
+        plugin.remove(repo)
+
+        self.assertFalse(os.path.exists(os.path.join(
+            self.path, 'repos', 'test.git', 'hooks', 'post-receive.default')))
+        self.assertTrue(os.path.exists(os.path.join(
+            self.path, 'repos', 'test.git', 'hooks', 'post-receive')))
+
+    def test_plugin_default_form(self):
+        """ Check that the default plugin's form.
+        """
+        with self._app.test_request_context('/') as ctx:
+            flask.g.session = self.session
+            flask.g.fas_user = tests.FakeUser(username='foo')
+
+            task = pagure.lib.new_project(
+                self.session,
+                user='pingou',
+                name='test',
+                blacklist=[],
+                allowed_prefix=[],
+                gitfolder=os.path.join(self.path, 'repos'),
+                docfolder=os.path.join(self.path, 'docs'),
+                ticketfolder=os.path.join(self.path, 'tickets'),
+                requestfolder=os.path.join(self.path, 'requests'),
+                description=None,
+                url=None, avatar_email=None,
+                parent_id=None,
+                add_readme=False,
+                userobj=None,
+                prevent_40_chars=False,
+                namespace=None
+            )
+            self.assertEqual(task.get(),
+                             {'endpoint': 'ui_ns.view_repo',
+                              'repo': 'test',
+                              'namespace': None})
+
+            repo = pagure.lib.get_authorized_project(self.session, 'test')
+            plugin = pagure.lib.plugins.get_plugin('default')
+            dbobj = plugin.db_object()
+            form = plugin.form(obj=dbobj)
+            self.assertEqual(
+                str(form.active),
+                '<input id="active" name="active" type="checkbox" value="y">'
+            )
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)

From 7056450fdeded9cfcec846190bc3bb7b88b21e4c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 8/15] Add more tests on the internal API checking if a PR can be merged


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_internal.py b/tests/test_pagure_flask_internal.py
index b17712f..11463c1 100644
--- a/tests/test_pagure_flask_internal.py
+++ b/tests/test_pagure_flask_internal.py
@@ -22,7 +22,7 @@ import time
 import os
 
 import pygit2
-from mock import patch
+from mock import patch, MagicMock
 
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
@@ -825,6 +825,23 @@ class PagureFlaskInternaltests(tests.Modeltests):
             data = {
                 'csrf_token': csrf_token,
                 'requestid': project.requests[0].uid,
+                'force': True,
+            }
+            output = self.app.post('/pv/pull-request/merge', data=data)
+            self.assertEqual(output.status_code, 200)
+            exp = {
+              "code": "MERGE",
+              "message": "The pull-request can be merged with a merge commit",
+              "short_code": "With merge"
+            }
+
+            js_data = json.loads(output.get_data(as_text=True))
+            self.assertDictEqual(js_data, exp)
+
+            # Asking a second time will trigger the cache
+            data = {
+                'csrf_token': csrf_token,
+                'requestid': project.requests[0].uid,
             }
             output = self.app.post('/pv/pull-request/merge', data=data)
             self.assertEqual(output.status_code, 200)
@@ -989,6 +1006,284 @@ class PagureFlaskInternaltests(tests.Modeltests):
             js_data = json.loads(output.get_data(as_text=True))
             self.assertDictEqual(js_data, exp)
 
+    @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
+    @patch(
+        'pagure.lib.git.merge_pull_request',
+        MagicMock(side_effect=pagure.exceptions.PagureException('error')))
+    def test_mergeable_request_pull_merge_pagureerror(self):
+        """ Test the mergeable_request_pull endpoint when the backend
+        raises an GitError exception.
+        """
+        # Create a git repo to play with
+
+        origgitrepo = os.path.join(self.path, 'repos', 'test.git')
+        self.assertFalse(os.path.exists(origgitrepo))
+        os.makedirs(origgitrepo)
+        orig_repo = pygit2.init_repository(origgitrepo, bare=True)
+        os.makedirs(os.path.join(self.path, 'repos_tmp'))
+        gitrepo = os.path.join(self.path, 'repos_tmp', 'test.git')
+        repo = pygit2.clone_repository(origgitrepo, gitrepo)
+
+        # Create a file in that git repo
+        with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
+            stream.write('foo\n bar')
+        repo.index.add('sources')
+        repo.index.write()
+
+        # Commits the files added
+        tree = repo.index.write_tree()
+        author = pygit2.Signature(
+            'Alice Author', 'alice@authors.tld')
+        committer = pygit2.Signature(
+            'Cecil Committer', 'cecil@committers.tld')
+        repo.create_commit(
+            'refs/heads/master',  # the name of the reference to update
+            author,
+            committer,
+            'Add sources file for testing',
+            # binary string representing the tree object ID
+            tree,
+            # list of binary strings representing parents of the new commit
+            []
+        )
+
+        first_commit = repo.revparse_single('HEAD')
+        refname = 'refs/heads/master:refs/heads/master'
+        ori_remote = repo.remotes[0]
+        PagureRepo.push(ori_remote, refname)
+
+        # Edit the sources file again
+        with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
+            stream.write('foo\n bar\nbaz\n boose')
+        repo.index.add('sources')
+        repo.index.write()
+
+        # Commits the files added
+        tree = repo.index.write_tree()
+        author = pygit2.Signature(
+            'Alice Author', 'alice@authors.tld')
+        committer = pygit2.Signature(
+            'Cecil Committer', 'cecil@committers.tld')
+        repo.create_commit(
+            'refs/heads/feature',  # the name of the reference to update
+            author,
+            committer,
+            'Add baz and boose to the sources\n\n There are more objects to '
+            'consider',
+            # binary string representing the tree object ID
+            tree,
+            # list of binary strings representing parents of the new commit
+            [first_commit.oid.hex]
+        )
+        refname = 'refs/heads/feature:refs/heads/feature'
+        ori_remote = repo.remotes[0]
+        PagureRepo.push(ori_remote, refname)
+
+        # Create another file in the master branch
+        with open(os.path.join(gitrepo, '.gitignore'), 'w') as stream:
+            stream.write('*~')
+        repo.index.add('.gitignore')
+        repo.index.write()
+
+        # Commits the files added
+        tree = repo.index.write_tree()
+        author = pygit2.Signature(
+            'Alice Author', 'alice@authors.tld')
+        committer = pygit2.Signature(
+            'Cecil Committer', 'cecil@committers.tld')
+        repo.create_commit(
+            'refs/heads/master',  # the name of the reference to update
+            author,
+            committer,
+            'Add .gitignore file for testing',
+            # binary string representing the tree object ID
+            tree,
+            # list of binary strings representing parents of the new commit
+            [first_commit.oid.hex]
+        )
+        refname = 'refs/heads/master:refs/heads/master'
+        ori_remote = repo.remotes[0]
+        PagureRepo.push(ori_remote, refname)
+
+        # Create a PR for these changes
+        tests.create_projects(self.session)
+        project = pagure.lib.get_authorized_project(self.session, 'test')
+        req = pagure.lib.new_pull_request(
+            session=self.session,
+            repo_from=project,
+            branch_from='feature',
+            repo_to=project,
+            branch_to='master',
+            title='PR from the feature branch',
+            user='pingou',
+            requestfolder=None,
+        )
+        self.session.commit()
+        self.assertEqual(req.id, 1)
+        self.assertEqual(req.title, 'PR from the feature branch')
+
+        # Check if the PR can be merged
+        data = {}
+
+        user = tests.FakeUser()
+        user.username = 'pingou'
+        with tests.user_set(self.app.application, user):
+            output = self.app.get('/test/adduser')
+            csrf_token = self.get_csrf(output=output)
+
+            # With all the desired information
+            project = pagure.lib.get_authorized_project(self.session, 'test')
+            data = {
+                'csrf_token': csrf_token,
+                'requestid': project.requests[0].uid,
+                'force': True,
+            }
+            output = self.app.post('/pv/pull-request/merge', data=data)
+            self.assertEqual(output.status_code, 500)
+            exp = {u'code': u'CONFLICTS', u'message': u'error'}
+
+            js_data = json.loads(output.get_data(as_text=True))
+            self.assertDictEqual(js_data, exp)
+
+    @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
+    @patch(
+        'pagure.lib.git.merge_pull_request',
+        MagicMock(side_effect=pygit2.GitError('git error')))
+    def test_mergeable_request_pull_merge_giterror(self):
+        """ Test the mergeable_request_pull endpoint when the backend
+        raises an GitError exception.
+        """
+        # Create a git repo to play with
+
+        origgitrepo = os.path.join(self.path, 'repos', 'test.git')
+        self.assertFalse(os.path.exists(origgitrepo))
+        os.makedirs(origgitrepo)
+        orig_repo = pygit2.init_repository(origgitrepo, bare=True)
+        os.makedirs(os.path.join(self.path, 'repos_tmp'))
+        gitrepo = os.path.join(self.path, 'repos_tmp', 'test.git')
+        repo = pygit2.clone_repository(origgitrepo, gitrepo)
+
+        # Create a file in that git repo
+        with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
+            stream.write('foo\n bar')
+        repo.index.add('sources')
+        repo.index.write()
+
+        # Commits the files added
+        tree = repo.index.write_tree()
+        author = pygit2.Signature(
+            'Alice Author', 'alice@authors.tld')
+        committer = pygit2.Signature(
+            'Cecil Committer', 'cecil@committers.tld')
+        repo.create_commit(
+            'refs/heads/master',  # the name of the reference to update
+            author,
+            committer,
+            'Add sources file for testing',
+            # binary string representing the tree object ID
+            tree,
+            # list of binary strings representing parents of the new commit
+            []
+        )
+
+        first_commit = repo.revparse_single('HEAD')
+        refname = 'refs/heads/master:refs/heads/master'
+        ori_remote = repo.remotes[0]
+        PagureRepo.push(ori_remote, refname)
+
+        # Edit the sources file again
+        with open(os.path.join(gitrepo, 'sources'), 'w') as stream:
+            stream.write('foo\n bar\nbaz\n boose')
+        repo.index.add('sources')
+        repo.index.write()
+
+        # Commits the files added
+        tree = repo.index.write_tree()
+        author = pygit2.Signature(
+            'Alice Author', 'alice@authors.tld')
+        committer = pygit2.Signature(
+            'Cecil Committer', 'cecil@committers.tld')
+        repo.create_commit(
+            'refs/heads/feature',  # the name of the reference to update
+            author,
+            committer,
+            'Add baz and boose to the sources\n\n There are more objects to '
+            'consider',
+            # binary string representing the tree object ID
+            tree,
+            # list of binary strings representing parents of the new commit
+            [first_commit.oid.hex]
+        )
+        refname = 'refs/heads/feature:refs/heads/feature'
+        ori_remote = repo.remotes[0]
+        PagureRepo.push(ori_remote, refname)
+
+        # Create another file in the master branch
+        with open(os.path.join(gitrepo, '.gitignore'), 'w') as stream:
+            stream.write('*~')
+        repo.index.add('.gitignore')
+        repo.index.write()
+
+        # Commits the files added
+        tree = repo.index.write_tree()
+        author = pygit2.Signature(
+            'Alice Author', 'alice@authors.tld')
+        committer = pygit2.Signature(
+            'Cecil Committer', 'cecil@committers.tld')
+        repo.create_commit(
+            'refs/heads/master',  # the name of the reference to update
+            author,
+            committer,
+            'Add .gitignore file for testing',
+            # binary string representing the tree object ID
+            tree,
+            # list of binary strings representing parents of the new commit
+            [first_commit.oid.hex]
+        )
+        refname = 'refs/heads/master:refs/heads/master'
+        ori_remote = repo.remotes[0]
+        PagureRepo.push(ori_remote, refname)
+
+        # Create a PR for these changes
+        tests.create_projects(self.session)
+        project = pagure.lib.get_authorized_project(self.session, 'test')
+        req = pagure.lib.new_pull_request(
+            session=self.session,
+            repo_from=project,
+            branch_from='feature',
+            repo_to=project,
+            branch_to='master',
+            title='PR from the feature branch',
+            user='pingou',
+            requestfolder=None,
+        )
+        self.session.commit()
+        self.assertEqual(req.id, 1)
+        self.assertEqual(req.title, 'PR from the feature branch')
+
+        # Check if the PR can be merged
+        data = {}
+
+        user = tests.FakeUser()
+        user.username = 'pingou'
+        with tests.user_set(self.app.application, user):
+            output = self.app.get('/test/adduser')
+            csrf_token = self.get_csrf(output=output)
+
+            # With all the desired information
+            project = pagure.lib.get_authorized_project(self.session, 'test')
+            data = {
+                'csrf_token': csrf_token,
+                'requestid': project.requests[0].uid,
+                'force': True,
+            }
+            output = self.app.post('/pv/pull-request/merge', data=data)
+            self.assertEqual(output.status_code, 409)
+            exp = {u'code': u'CONFLICTS', u'message': u'git error'}
+
+            js_data = json.loads(output.get_data(as_text=True))
+            self.assertDictEqual(js_data, exp)
+
     def test_get_branches_of_commit(self):
         ''' Test the get_branches_of_commit from the internal API. '''
         tests.create_projects(self.session)

From ea47176a882d53043776be7f4e40b65270f7351c Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 9/15] Add tests for the get_pull_request_ready_branch


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_internal.py b/tests/test_pagure_flask_internal.py
index 11463c1..57d48f9 100644
--- a/tests/test_pagure_flask_internal.py
+++ b/tests/test_pagure_flask_internal.py
@@ -2157,6 +2157,57 @@ class PagureFlaskInternaltests(tests.Modeltests):
             js_data['family'],
             ['test', 'fork/ralph/test'])
 
+    def test_get_pull_request_ready_branch_no_csrf(self):
+        '''Test the get_pull_request_ready_branch from the internal API
+        on the main repository
+        '''
+        tests.create_projects(self.session)
+        tests.create_projects_git(
+            os.path.join(self.path, 'repos'), bare=True)
+
+        # Query branches on the main repo
+        data = {
+            'repo': 'test',
+        }
+        output = self.app.post('/pv/pull-request/ready', data=data)
+        self.assertEqual(output.status_code, 400)
+        js_data = json.loads(output.get_data(as_text=True))
+        self.assertEqual(
+            sorted(js_data.keys()),
+            ['code', 'message']
+        )
+        self.assertEqual(js_data['code'], 'ERROR')
+        self.assertEqual(
+            js_data['message'],
+            'Invalid input submitted'
+        )
+
+    def test_get_pull_request_ready_branch_no_repo(self):
+        '''Test the get_pull_request_ready_branch from the internal API
+        on the main repository
+        '''
+        with tests.user_set(self.app.application, tests.FakeUser()):
+            csrf_token = self.get_csrf()
+
+        # Query branches on an invalid repo
+        data = {
+            'repo': 'test',
+            'namespace': 'fake',
+            'csrf_token': csrf_token,
+        }
+        output = self.app.post('/pv/pull-request/ready', data=data)
+        self.assertEqual(output.status_code, 404)
+        js_data = json.loads(output.get_data(as_text=True))
+        self.assertEqual(
+            sorted(js_data.keys()),
+            ['code', 'message']
+        )
+        self.assertEqual(js_data['code'], 'ERROR')
+        self.assertEqual(
+            js_data['message'],
+            'No repo found with the information provided'
+        )
+
     def test_get_pull_request_ready_branch_main_repo_no_branch(self):
         '''Test the get_pull_request_ready_branch from the internal API
         on the main repository

From 9262b7af6d06654484304d4cb2fa501695da8b60 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 10/15] Drop unused section of code


We check the existence of the project earlier in the code

Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/pagure/internal/__init__.py b/pagure/internal/__init__.py
index 0853793..79f56f9 100644
--- a/pagure/internal/__init__.py
+++ b/pagure/internal/__init__.py
@@ -393,14 +393,6 @@ def get_ticket_template(repo, namespace=None, username=None):
     repo = pagure.lib.get_authorized_project(
         flask.g.session, repo, user=username, namespace=namespace)
 
-    if repo is None:
-        response = flask.jsonify({
-            'code': 'ERROR',
-            'message': 'Project not found',
-        })
-        response.status_code = 404
-        return response
-
     if not repo.settings.get('issue_tracker', True):
         response = flask.jsonify({
             'code': 'ERROR',

From a3de6440e8a1e485a89f8c61719e085cbd682e0b Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 11/15] Add unit-tests for the task_info internal API endpoint


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_internal.py b/tests/test_pagure_flask_internal.py
index 57d48f9..706a3a1 100644
--- a/tests/test_pagure_flask_internal.py
+++ b/tests/test_pagure_flask_internal.py
@@ -22,7 +22,7 @@ import time
 import os
 
 import pygit2
-from mock import patch, MagicMock
+from mock import patch, MagicMock, Mock
 
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
@@ -2553,6 +2553,39 @@ class PagureFlaskInternaltests(tests.Modeltests):
         self.assertEqual(
             js_data['message']['new_branch']['feature']['target_branch'], 'feature')
 
+    def test_task_info_task_running(self):
+        """ Test the task_info internal API endpoint when the task isn't
+        ready.
+        """
+        task = MagicMock()
+        task.get = MagicMock(return_value='FAILED')
+        task.ready = MagicMock(return_value=False)
+        with patch('pagure.lib.tasks.get_result', MagicMock(return_value=task)):
+            output = self.app.get('/pv/task/2')
+            self.assertEqual(output.status_code, 418)
+
+    def test_task_info_task_passed(self):
+        """ Test the task_info internal API endpoint when the task failed.
+        """
+        task = MagicMock()
+        task.get = MagicMock(return_value='PASSED')
+        with patch('pagure.lib.tasks.get_result', MagicMock(return_value=task)):
+            output = self.app.get('/pv/task/2')
+            self.assertEqual(output.status_code, 200)
+            js_data = json.loads(output.get_data(as_text=True))
+            self.assertEqual(js_data, {u'results': u'PASSED'})
+
+    def test_task_info_task_failed(self):
+        """ Test the task_info internal API endpoint when the task failed.
+        """
+        task = MagicMock()
+        task.get = MagicMock(return_value=Exception('Random error'))
+        with patch('pagure.lib.tasks.get_result', MagicMock(return_value=task)):
+            output = self.app.get('/pv/task/2')
+            self.assertEqual(output.status_code, 200)
+            js_data = json.loads(output.get_data(as_text=True))
+            self.assertEqual(js_data, {u'results': u'Random error'})
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)

From 689da110cde3c39f1d768c75c39708cbe7479d19 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 12/15] Expand the unit-tests about the internal endpoint for a project's templates


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_ui_issues_templates.py b/tests/test_pagure_flask_ui_issues_templates.py
index b3e6e3e..ae57ad4 100644
--- a/tests/test_pagure_flask_ui_issues_templates.py
+++ b/tests/test_pagure_flask_ui_issues_templates.py
@@ -108,14 +108,14 @@ def create_templates(repopath):
     )
 
 
-class PagureFlaskIssuestests(tests.Modeltests):
+class PagureFlaskIssuesTemplatetests(tests.Modeltests):
     """ Tests for flask issues controller of pagure """
 
     @patch('pagure.lib.git.update_git', MagicMock(return_value=True))
     @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
     def setUp(self):
         """ Set up the environnment, run before every tests. """
-        super(PagureFlaskIssuestests, self).setUp()
+        super(PagureFlaskIssuesTemplatetests, self).setUp()
 
         pagure.config.config['TICKETS_FOLDER'] = os.path.join(
             self.path, 'tickets')
@@ -206,8 +206,8 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 {"code": "ERROR", "message": "No template provided"})
 
     def test_get_ticket_template_no_project(self):
-        """ Test the get_ticket_template endpoint when not specifying which
-        template to get.
+        """ Test the get_ticket_template endpoint when the project does not
+        exist.
         """
 
         user = tests.FakeUser()
@@ -215,7 +215,7 @@ class PagureFlaskIssuestests(tests.Modeltests):
             csrf = self.get_csrf()
             data = {'csrf_token': csrf}
             output = self.app.post(
-                '/pv/test/issue/template?template=RFE', data=data)
+                '/pv/foobar/issue/template', data=data)
             self.assertEqual(output.status_code, 404)
 
     def test_get_ticket_template_no_template(self):
@@ -235,6 +235,33 @@ class PagureFlaskIssuestests(tests.Modeltests):
                 data,
                 {"code": "ERROR", "message": "No such template found"})
 
+    def test_get_ticket_template_issue_tracker_disabled(self):
+        """ Test the get_ticket_template endpoint when the project has
+        disabled its issue tracker.
+        """
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        settings = repo.settings
+        settings['issue_tracker'] = False
+        repo.settings = settings
+        self.session.add(repo)
+        self.session.commit()
+
+        user = tests.FakeUser()
+        with tests.user_set(self.app.application, user):
+            csrf = self.get_csrf()
+            data = {'csrf_token': csrf}
+            output = self.app.post(
+                '/pv/test/issue/template?template=RFE', data=data)
+            self.assertEqual(output.status_code, 404)
+            data = json.loads(output.get_data(as_text=True))
+            self.assertEqual(
+                data,
+                {
+                    u'code': u'ERROR',
+                    u'message': u'No issue tracker found for this project'
+                }
+            )
+
     def test_get_ticket_template_w_template(self):
         """ Test the get_ticket_template endpoint when the project has
         templates.

From 3a70728e429702a6fa2c3cfa6853a655fc87859a Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 13/15] Remove never used code


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/pagure/api/issue.py b/pagure/api/issue.py
index 7a11a89..c699ab4 100644
--- a/pagure/api/issue.py
+++ b/pagure/api/issue.py
@@ -1083,10 +1083,6 @@ def api_assign_issue(repo, issueid, username=None, namespace=None):
             _log.exception(err)
             raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)
 
-    else:
-        raise pagure.exceptions.APIError(
-            400, error_code=APIERROR.EINVALIDREQ, errors=form.errors)
-
     jsonout = flask.jsonify(output)
     return jsonout
 
@@ -1166,10 +1162,6 @@ def api_subscribe_issue(repo, issueid, username=None, namespace=None):
             _log.exception(err)
             raise pagure.exceptions.APIError(400, error_code=APIERROR.EDBERROR)
 
-    else:
-        raise pagure.exceptions.APIError(
-            400, error_code=APIERROR.EINVALIDREQ, errors=form.errors)
-
     jsonout = flask.jsonify(output)
     return jsonout
 

From aa57b32d4921d281f53c0ded0ea94da37b626bc5 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 09:36:52 +0000
Subject: [PATCH 14/15] Add tests when updating custom fields via the API raises an exception


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/test_pagure_flask_api_issue.py b/tests/test_pagure_flask_api_issue.py
index f5ee7d0..910ce64 100644
--- a/tests/test_pagure_flask_api_issue.py
+++ b/tests/test_pagure_flask_api_issue.py
@@ -3632,6 +3632,65 @@ class PagureFlaskApiIssuetests(tests.SimplePagureTest):
         issue = pagure.lib.search_issues(self.session, repo, issueid=1)
         self.assertEqual(len(issue.other_fields), 0)
 
+    @patch(
+        'pagure.lib.set_custom_key_value',
+        MagicMock(side_effect=pagure.exceptions.PagureException('error')))
+    def test_api_update_custom_field_raises_error(self):
+        """ Test the api_update_custom_field method of the flask api. """
+        tests.create_projects(self.session)
+        tests.create_projects_git(os.path.join(self.path, 'tickets'))
+        tests.create_tokens(self.session)
+        tests.create_tokens_acl(self.session)
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+
+        # Create normal issue
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.new_issue(
+            session=self.session,
+            repo=repo,
+            title='Test issue #1',
+            content='We should work on this',
+            user='pingou',
+            ticketfolder=None,
+            private=False,
+        )
+        self.session.commit()
+        self.assertEqual(msg.title, 'Test issue #1')
+
+        # Set some custom fields
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.set_custom_key_fields(
+            self.session, repo,
+            ['bugzilla', 'upstream', 'reviewstatus'],
+            ['link', 'boolean', 'list'],
+            ['unused data for non-list type', '', 'ack, nack ,  needs review'],
+            [None, None, None])
+        self.session.commit()
+        self.assertEqual(msg, 'List of custom fields updated')
+
+        # Check the project custom fields were correctly set
+        for key in repo.issue_keys:
+            # Check that the bugzilla field correctly had its data removed
+            if key.name == "bugzilla":
+                self.assertIsNone(key.data)
+
+            # Check that the reviewstatus list field still has its list
+            elif key.name == "reviewstatus":
+                self.assertEqual(
+                    sorted(key.data), ['ack', 'nack', 'needs review'])
+
+        # Should work but raises an exception
+        output = self.app.post(
+            '/api/0/test/issue/1/custom/bugzilla', headers=headers,
+            data={'value': 'https://bugzilla.redhat.com/1234'})
+        self.assertEqual(output.status_code, 400)
+        data = json.loads(output.get_data(as_text=True))
+        self.assertDictEqual(
+            data,
+            {u'error': u'error', u'error_code': u'ENOCODE'}
+        )
+
     def test_api_view_issues_history_stats(self):
         """ Test the api_view_issues_history_stats method of the flask api. """
         self.test_api_new_issue()
diff --git a/tests/test_pagure_flask_api_issue_custom_fields.py b/tests/test_pagure_flask_api_issue_custom_fields.py
index c1a2500..ccb831d 100644
--- a/tests/test_pagure_flask_api_issue_custom_fields.py
+++ b/tests/test_pagure_flask_api_issue_custom_fields.py
@@ -13,6 +13,7 @@ import sys
 import os
 import json
 
+from mock import patch, MagicMock
 
 sys.path.insert(0, os.path.join(os.path.dirname(
     os.path.abspath(__file__)), '..'))
@@ -24,6 +25,7 @@ import tests  # noqa: E402
 
 class PagureFlaskApiCustomFieldIssuetests(tests.Modeltests):
     """ Tests for the flask API of pagure for issue's custom fields """
+
     def setUp(self):
         """ Set up the environnment, ran before every tests. """
         self.maxDiff = None
@@ -90,6 +92,35 @@ class PagureFlaskApiCustomFieldIssuetests(tests.Modeltests):
             }
         )
 
+    @patch(
+        'pagure.lib.set_custom_key_value',
+        MagicMock(side_effect=pagure.exceptions.PagureException('error')))
+    def test_api_update_custom_field_raise_error(self):
+        """ Test the api_update_custom_field method of the flask api.
+        This test the successful requests scenarii.
+        """
+
+        headers = {'Authorization': 'token aaabbbcccddd'}
+
+        # Set some custom fields
+        repo = pagure.lib.get_authorized_project(self.session, 'test')
+        msg = pagure.lib.set_custom_key_fields(
+            self.session, repo,
+            ['bugzilla', 'upstream', 'reviewstatus'],
+            ['link', 'boolean', 'list'],
+            ['unused data for non-list type', '', 'ack', 'nack', 'needs review'],
+            [None, None, None])
+        self.session.commit()
+        self.assertEqual(msg, 'List of custom fields updated')
+
+        payload = {'bugzilla': '', 'upstream': True}
+        output = self.app.post(
+            '/api/0/test/issue/1/custom', headers=headers, data=payload)
+        self.assertEqual(output.status_code, 400)
+        data = json.loads(output.get_data(as_text=True))
+        self.assertDictEqual(
+            data, {u'error': u'error', u'error_code': u'ENOCODE'})
+
     def test_api_update_custom_field(self):
         """ Test the api_update_custom_field method of the flask api.
         This test the successful requests scenarii.

From 2cca8378b834f1a22369b3ff596e31a1bfc56563 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Aug 02 2018 13:57:56 +0000
Subject: [PATCH 15/15] Fix invalid py3 code


Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/pagure/internal/__init__.py b/pagure/internal/__init__.py
index 79f56f9..c62cee8 100644
--- a/pagure/internal/__init__.py
+++ b/pagure/internal/__init__.py
@@ -227,12 +227,12 @@ def mergeable_request_pull():
             domerge=False)
     except pygit2.GitError as err:
         response = flask.jsonify({
-            'code': 'CONFLICTS', 'message': err.message})
+            'code': 'CONFLICTS', 'message': '%s' % err})
         response.status_code = 409
         return response
     except pagure.exceptions.PagureException as err:
         response = flask.jsonify({
-            'code': 'CONFLICTS', 'message': err.message})
+            'code': 'CONFLICTS', 'message': '%s' % err})
         response.status_code = 500
         return response
 

