From 5460c9c2c73a2fff0cc4098e174c01735ed091b6 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 05 2018 15:04:31 +0000 Subject: [PATCH 1/7] Fix error in the call to the logger Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/api/project.py b/pagure/api/project.py index 0f72ab0..3f3a5a5 100644 --- a/pagure/api/project.py +++ b/pagure/api/project.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - (c) 2015 - Copyright Red Hat Inc + (c) 2015-2018 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon @@ -1453,7 +1453,7 @@ def api_commit_add_flag(repo, commit_hash, username=None, namespace=None): 400, error_code=APIERROR.ENOCODE, error=str(err)) except SQLAlchemyError as err: # pragma: no cover flask.g.session.rollback() - _log.logger.exception(err) + _log.exception(err) raise pagure.exceptions.APIError( 400, error_code=APIERROR.EDBERROR) else: From 4b80772b7193f868de25b4a97dedcc06f8db203e Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 05 2018 15:04:31 +0000 Subject: [PATCH 2/7] Add an option to notify on flags being added to a pull-request Relates to #2947 Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 03a2aea..636d5e0 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - (c) 2014-2017 - Copyright Red Hat Inc + (c) 2014-2018 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon @@ -1376,6 +1376,9 @@ def add_pull_request_flag(session, request, username, percent, comment, url, # Make sure we won't have SQLAlchemy error before we continue session.flush() + if request.project.settings.get('notify_on_pull-request_flag'): + pagure.lib.notify.notify_pull_request_flag(pr_flag, username) + pagure.lib.git.update_git( request, repo=request.project, repofolder=requestfolder) diff --git a/pagure/lib/model.py b/pagure/lib/model.py index 75534dd..f5c9430 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - (c) 2014-2017 - Copyright Red Hat Inc + (c) 2014-2018 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon @@ -520,6 +520,7 @@ class Project(BASE): 'fedmsg_notifications': True, 'pull_request_access_only': False, 'roadmap_on_issues_page': False, + 'notify_on_pull-request_flag': False, } if self._settings: diff --git a/pagure/lib/notify.py b/pagure/lib/notify.py index 5867d68..9030e09 100644 --- a/pagure/lib/notify.py +++ b/pagure/lib/notify.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - (c) 2014-2017 - Copyright Red Hat Inc + (c) 2014-2018 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon @@ -677,6 +677,36 @@ def notify_pull_request_comment(comment, user): ) +def notify_pull_request_flag(flag, user): + ''' Notify the people following a pull-request that a new flag was + added to it. + ''' + text = u""" +%s flagged the pull-request `%s` as %s: %s + +%s +""" % (flag.username, + flag.pull_request.title, + flag.status, + flag.comment, + _build_url( + pagure_config['APP_URL'], + _fullname_to_url(flag.pull_request.project.fullname), + 'pull-request', + flag.pull_request.id)) + mail_to = _get_emails_for_obj(flag.pull_request) + + send_email( + text, + 'PR #%s: %s' % (flag.pull_request.id, flag.pull_request.title), + ','.join(mail_to), + mail_id=flag.mail_id, + in_reply_to=flag.pull_request.mail_id, + project_name=flag.pull_request.project.fullname, + user_from=flag.username, + ) + + def notify_new_email(email, user): ''' Ask the user to confirm to the email belong to them. ''' From 327b884a445d1f5c489a6b9fe8aff19ab6c7af22 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 05 2018 15:04:31 +0000 Subject: [PATCH 3/7] Add an option to notify on flags being added to a commit Fixes to #2947 Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 636d5e0..29d1841 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -1427,6 +1427,9 @@ def add_commit_flag( # Make sure we won't have SQLAlchemy error before we continue session.flush() + if repo.settings.get('notify_on_commit_flag'): + pagure.lib.notify.notify_commit_flag(c_flag, username) + pagure.lib.notify.log( repo, topic='commit.flag.%s' % action, diff --git a/pagure/lib/model.py b/pagure/lib/model.py index f5c9430..57915dd 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -469,6 +469,13 @@ class Project(BASE): return 'project' @property + def mail_id(self): + ''' Return a unique representation of the project as string that + can be used when sending emails. + ''' + return '%s-project-%s' % (self.fullname, self.id) + + @property def path(self): ''' Return the name of the git repo on the filesystem. ''' return '%s.git' % self.fullname @@ -521,6 +528,7 @@ class Project(BASE): 'pull_request_access_only': False, 'roadmap_on_issues_page': False, 'notify_on_pull-request_flag': False, + 'notify_on_commit_flag': False, } if self._settings: @@ -2035,6 +2043,14 @@ class PullRequestFlag(BASE): foreign_keys=[pull_request_uid], remote_side=[PullRequest.uid]) + @property + def mail_id(self): + ''' Return a unique representation of the flag as string that + can be used when sending emails. + ''' + return '%s-pull-request-%s-%s' % ( + self.pull_request.project.name, self.pull_request.uid, self.id) + def to_json(self, public=False): ''' Returns a dictionary representation of the pull-request. @@ -2103,12 +2119,32 @@ class CommitFlag(BASE): __table_args__ = (sa.UniqueConstraint('commit_hash', 'uid'),) + project = relation( + 'Project', foreign_keys=[project_id], remote_side=[Project.id], + backref=backref( + 'commit_flags', cascade="delete, delete-orphan", + ), + single_parent=True) + user = relation('User', foreign_keys=[user_id], remote_side=[User.id], backref=backref( 'commit_flags', order_by="CommitFlag.date_created")) + @property + def isa(self): + ''' A string to allow finding out that this is a commit flag. ''' + return 'commit-flag' + + @property + def mail_id(self): + ''' Return a unique representation of the flag as string that + can be used when sending emails. + ''' + return '%s-commit-%s-%s' % ( + self.project.name, self.project.id, self.id) + def to_json(self, public=False): ''' Returns a dictionary representation of the commit flag. diff --git a/pagure/lib/notify.py b/pagure/lib/notify.py index 9030e09..42d8e3a 100644 --- a/pagure/lib/notify.py +++ b/pagure/lib/notify.py @@ -128,17 +128,19 @@ def _get_emails_for_obj(obj): emails.add(user.default_email) # Add people that commented on the issue/PR - for comment in obj.comments: - if comment.user.default_email: - emails.add(comment.user.default_email) + if obj.isa in ['issue', 'pull-request']: + for comment in obj.comments: + if comment.user.default_email: + emails.add(comment.user.default_email) # Add the person that opened the issue/PR if obj.user.default_email: emails.add(obj.user.default_email) # Add the person assigned to the issue/PR - if obj.assignee and obj.assignee.default_email: - emails.add(obj.assignee.default_email) + if obj.isa in ['issue', 'pull-request']: + if obj.assignee and obj.assignee.default_email: + emails.add(obj.assignee.default_email) # Add public notifications to lists/users set project-wide if obj.isa == 'issue' and not obj.private: @@ -161,11 +163,12 @@ def _get_emails_for_obj(obj): emails.remove(watcher.user.default_email) # Add/Remove people who explicitly asked to be added/removed - for watcher in obj.watchers: - if not watcher.watch and watcher.user.default_email in emails: - emails.remove(watcher.user.default_email) - elif watcher.watch: - emails.add(watcher.user.default_email) + if obj.isa in ['issue', 'pull-request']: + for watcher in obj.watchers: + if not watcher.watch and watcher.user.default_email in emails: + emails.remove(watcher.user.default_email) + elif watcher.watch: + emails.add(watcher.user.default_email) # Drop the email used by pagure when sending emails = _clean_emails( @@ -783,3 +786,34 @@ To view more about the commits, visit: ','.join(mail_to), project_name=project.fullname ) + + +def notify_commit_flag(flag, user): + ''' Notify the people following a project that a new flag was added + to one of its commit. + ''' + text = u""" +%s flagged the commit `%s` as %s: %s + +%s +""" % (flag.username, + flag.commit_hash, + flag.status, + flag.comment, + _build_url( + pagure_config['APP_URL'], + _fullname_to_url(flag.project.fullname), + 'c', + flag.commit_hash)) + mail_to = _get_emails_for_obj(flag) + + send_email( + text, + 'Coommit #%s - %s: %s' % ( + flag.commit_hash, flag.username, flag.status), + ','.join(mail_to), + mail_id=flag.mail_id, + in_reply_to=flag.project.mail_id, + project_name=flag.project.fullname, + user_from=flag.username, + ) From af53435fbf253296d4be78fb4324062bf8ce3777 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 05 2018 15:04:31 +0000 Subject: [PATCH 4/7] Fix typo in docstring Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/lib/model.py b/pagure/lib/model.py index 57915dd..f95779b 100644 --- a/pagure/lib/model.py +++ b/pagure/lib/model.py @@ -1948,7 +1948,7 @@ class PullRequestComment(BASE): @property def mail_id(self): - ''' Return a unique reprensetation of the issue as string that + ''' Return a unique representation of the issue as string that can be used when sending emails. ''' return '%s-pull-request-%s-%s' % ( From 402026ba28f63229363ce11a476a577fe1e3a366 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 05 2018 15:04:31 +0000 Subject: [PATCH 5/7] fixup pr flag --- diff --git a/pagure/lib/notify.py b/pagure/lib/notify.py index 42d8e3a..e744d14 100644 --- a/pagure/lib/notify.py +++ b/pagure/lib/notify.py @@ -701,7 +701,8 @@ def notify_pull_request_flag(flag, user): send_email( text, - 'PR #%s: %s' % (flag.pull_request.id, flag.pull_request.title), + 'PR #%s - %s: %s' % ( + flag.pull_request.id, flag.username, flag.status), ','.join(mail_to), mail_id=flag.mail_id, in_reply_to=flag.pull_request.mail_id, From 6882b8d30a8e3bd3978d1688bca2b11d28a77f6d Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 05 2018 15:04:31 +0000 Subject: [PATCH 6/7] Add unit-tests for the notification sent on commit flag being added Signed-off-by: Pierre-Yves Chibon --- diff --git a/tests/test_pagure_flask_api_project.py b/tests/test_pagure_flask_api_project.py index 8fc0c1e..af4aad3 100644 --- a/tests/test_pagure_flask_api_project.py +++ b/tests/test_pagure_flask_api_project.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - (c) 2015-2017 - Copyright Red Hat Inc + (c) 2015-2018 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon @@ -2972,8 +2972,12 @@ class PagureFlaskApiProjectFlagtests(tests.Modeltests): self.assertEqual(data, expected_output) - def test_flag_commit_without_uid(self): - """ Test flagging a commit with missing info. """ + @patch('pagure.lib.notify.send_email') + def test_flag_commit_without_uid(self, mock_email): + """ Test flagging a commit with missing info. + + Also ensure notifications aren't sent when they are not asked for. + """ repo_obj = pygit2.Repository(self.git_path) commit = repo_obj.revparse_single('HEAD') @@ -2995,12 +2999,11 @@ class PagureFlaskApiProjectFlagtests(tests.Modeltests): u'jenkins_build_pagure_100+seed' ) data['flag']['date_created'] = u'1510742565' - data['flag']['commit_hash'] = u'62b49f00d489452994de5010565fab81' data['uid'] = 'b1de8f80defd4a81afe2e09f39678087' expected_output = { u'flag': { u'comment': u'Tests passed', - u'commit_hash': u'62b49f00d489452994de5010565fab81', + u'commit_hash': commit.oid.hex, u'date_created': u'1510742565', u'percent': 100, u'status': 'success', @@ -3017,6 +3020,75 @@ class PagureFlaskApiProjectFlagtests(tests.Modeltests): } self.assertEqual(data, expected_output) + mock_email.assert_not_called() + + @patch('pagure.lib.notify.send_email') + def test_flag_commit_with_notification(self, mock_email): + """ Test flagging a commit with notification enabled. """ + + # Enable commit notifications + repo = pagure.lib.get_authorized_project(self.session, 'test') + settings = repo.settings + settings['notify_on_commit_flag'] = True + repo.settings = settings + self.session.add(repo) + self.session.commit() + + repo_obj = pygit2.Repository(self.git_path) + commit = repo_obj.revparse_single('HEAD') + + headers = {'Authorization': 'token aaabbbcccddd'} + data = { + 'username': 'Jenkins', + 'percent': 100, + 'comment': 'Tests passed', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'status': 'success', + } + output = self.app.post( + '/api/0/test/c/%s/flag' % commit.oid.hex, + headers=headers, data=data) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + self.assertNotEqual( + data['uid'], + u'jenkins_build_pagure_100+seed' + ) + data['flag']['date_created'] = u'1510742565' + data['uid'] = 'b1de8f80defd4a81afe2e09f39678087' + expected_output = { + u'flag': { + u'comment': u'Tests passed', + u'commit_hash': commit.oid.hex, + u'date_created': u'1510742565', + u'percent': 100, + u'status': 'success', + u'url': u'http://jenkins.cloud.fedoraproject.org/', + u'user': { + u'default_email': u'bar@pingou.com', + u'emails': [u'bar@pingou.com', u'foo@pingou.com'], + u'fullname': u'PY C', + u'name': u'pingou'}, + u'username': u'Jenkins' + }, + u'message': u'Flag added', + u'uid': u'b1de8f80defd4a81afe2e09f39678087' + } + self.assertEqual(data, expected_output) + + mock_email.assert_called_once_with( + u'\nJenkins flagged the commit ' + u'`' + commit.oid.hex + u'` as success: ' + u'Tests passed\n\n' + u'https://pagure.org/test/c/' + commit.oid.hex + u'\n', + u'Coommit #' + commit.oid.hex + u' - Jenkins: success', + u'bar@pingou.com', + in_reply_to=u'test-project-1', + mail_id=u'test-commit-1-1', + project_name=u'test', + user_from=u'Jenkins' + ) + if __name__ == '__main__': unittest.main(verbosity=2) From 3ffb2e70c9696b8c5ce473e6a8257e009c25cfc8 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 05 2018 15:04:31 +0000 Subject: [PATCH 7/7] Move the unit-tests for flagging PR to their own file and expand them This commit in addition to moving the old tests to their own file also restructures them so they do less and are better documented. It also add some tests for the notifications being sent when a project opts in to notification on PR flags. Signed-off-by: Pierre-Yves Chibon --- diff --git a/tests/test_pagure_flask_api_fork.py b/tests/test_pagure_flask_api_fork.py index 5a4eb8c..b793a61 100644 --- a/tests/test_pagure_flask_api_fork.py +++ b/tests/test_pagure_flask_api_fork.py @@ -961,425 +961,6 @@ class PagureFlaskApiForktests(tests.Modeltests): self.session, project_id=1, requestid=1) self.assertEqual(len(request.comments), 1) - @patch('pagure.lib.notify.send_email') - def test_api_pull_request_add_flag(self, mockemail): - """ Test the api_pull_request_add_flag method of the flask api. """ - mockemail.return_value = True - - tests.create_projects(self.session) - tests.create_tokens(self.session) - tests.create_tokens_acl(self.session) - - headers = {'Authorization': 'token aaabbbcccddd'} - - # Invalid project - output = self.app.post( - '/api/0/foo/pull-request/1/flag', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Project not found", - "error_code": "ENOPROJECT", - } - ) - - # Valid token, wrong project - output = self.app.post( - '/api/0/test2/pull-request/1/flag', headers=headers) - self.assertEqual(output.status_code, 401) - data = json.loads(output.data) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, - data['error_code']) - self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) - - # No input - output = self.app.post( - '/api/0/test/pull-request/1/flag', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Pull-Request not found", - "error_code": "ENOREQ", - } - ) - - # Create a pull-request - repo = pagure.lib.get_authorized_project(self.session, 'test') - forked_repo = pagure.lib.get_authorized_project(self.session, 'test') - req = pagure.lib.new_pull_request( - session=self.session, - repo_from=forked_repo, - branch_from='master', - repo_to=repo, - branch_to='master', - title='test pull-request', - user='pingou', - requestfolder=None, - ) - self.session.commit() - self.assertEqual(req.id, 1) - self.assertEqual(req.title, 'test pull-request') - - # Check comments before - self.session = pagure.lib.create_session(self.dbpath) - request = pagure.lib.search_pull_requests( - self.session, project_id=1, requestid=1) - self.assertEqual(len(request.flags), 0) - - data = { - 'username': 'Jenkins', - 'percent': 100, - 'url': 'http://jenkins.cloud.fedoraproject.org/', - 'uid': 'jenkins_build_pagure_100+seed', - } - - # Incomplete request - output = self.app.post( - '/api/0/test/pull-request/1/flag', data=data, headers=headers) - self.assertEqual(output.status_code, 400) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Invalid or incomplete input submitted", - "error_code": "EINVALIDREQ", - "errors": {"comment": ["This field is required."]} - } - ) - - # No change - self.session = pagure.lib.create_session(self.dbpath) - request = pagure.lib.search_pull_requests( - self.session, project_id=1, requestid=1) - self.assertEqual(len(request.flags), 0) - - data = { - 'username': 'Jenkins', - 'comment': 'Tests running', - 'url': 'http://jenkins.cloud.fedoraproject.org/', - 'uid': 'jenkins_build_pagure_100+seed', - } - - # Valid request - output = self.app.post( - '/api/0/test/pull-request/1/flag', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - data['flag']['date_created'] = u'1510742565' - data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' - self.assertDictEqual( - data, - { - u'flag': { - u'comment': u'Tests running', - u'date_created': u'1510742565', - u'percent': None, - u'pull_request_uid': u'62b49f00d489452994de5010565fab81', - u'status': u'pending', - u'url': u'http://jenkins.cloud.fedoraproject.org/', - u'user': { - u'default_email': u'bar@pingou.com', - u'emails': [u'bar@pingou.com', u'foo@pingou.com'], - u'fullname': u'PY C', - u'name': u'pingou'}, - u'username': u'Jenkins'}, - u'message': u'Flag added', - u'uid': u'jenkins_build_pagure_100+seed' - } - ) - - # One flag added - self.session = pagure.lib.create_session(self.dbpath) - request = pagure.lib.search_pull_requests( - self.session, project_id=1, requestid=1) - self.assertEqual(len(request.flags), 1) - self.assertEqual(request.flags[0].comment, 'Tests running') - self.assertEqual(request.flags[0].percent, None) - - # Update flag - w/o providing the status - data = { - 'username': 'Jenkins', - 'percent': 100, - 'comment': 'Tests passed', - 'url': 'http://jenkins.cloud.fedoraproject.org/', - 'uid': 'jenkins_build_pagure_100+seed', - } - - output = self.app.post( - '/api/0/test/pull-request/1/flag', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - data['flag']['date_created'] = u'1510742565' - data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' - self.assertDictEqual( - data, - { - u'flag': { - u'comment': u'Tests passed', - u'date_created': u'1510742565', - u'percent': 100, - u'pull_request_uid': u'62b49f00d489452994de5010565fab81', - u'status': u'success', - u'url': u'http://jenkins.cloud.fedoraproject.org/', - u'user': { - u'default_email': u'bar@pingou.com', - u'emails': [u'bar@pingou.com', u'foo@pingou.com'], - u'fullname': u'PY C', - u'name': u'pingou'}, - u'username': u'Jenkins'}, - u'message': u'Flag updated', - u'uid': u'jenkins_build_pagure_100+seed' - } - ) - - # One flag added - self.session = pagure.lib.create_session(self.dbpath) - request = pagure.lib.search_pull_requests( - self.session, project_id=1, requestid=1) - self.assertEqual(len(request.flags), 1) - self.assertEqual(request.flags[0].comment, 'Tests passed') - self.assertEqual(request.flags[0].percent, 100) - - data = { - 'username': 'Jenkins', - 'comment': 'Tests running again', - 'url': 'http://jenkins.cloud.fedoraproject.org/', - } - - # Valid request - output = self.app.post( - '/api/0/test/pull-request/1/flag', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - data['flag']['date_created'] = u'1510742565' - data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' - self.assertNotEqual( - data['uid'], 'jenkins_build_pagure_100+seed') - data['uid'] = 'jenkins_build_pagure_100+seed' - self.assertDictEqual( - data, - { - u'flag': { - u'comment': u'Tests running again', - u'date_created': u'1510742565', - u'percent': None, - u'pull_request_uid': u'62b49f00d489452994de5010565fab81', - u'status': u'pending', - u'url': u'http://jenkins.cloud.fedoraproject.org/', - u'user': { - u'default_email': u'bar@pingou.com', - u'emails': [u'bar@pingou.com', u'foo@pingou.com'], - u'fullname': u'PY C', - u'name': u'pingou'}, - u'username': u'Jenkins'}, - u'message': u'Flag added', - u'uid': u'jenkins_build_pagure_100+seed' - } - ) - - # Two flag added - self.session = pagure.lib.create_session(self.dbpath) - request = pagure.lib.search_pull_requests( - self.session, project_id=1, requestid=1) - self.assertEqual(len(request.flags), 2) - self.assertEqual(request.flags[0].comment, 'Tests passed') - self.assertEqual(request.flags[0].percent, 100) - self.assertEqual(request.flags[1].comment, 'Tests running again') - self.assertEqual(request.flags[1].percent, None) - - @patch('pagure.lib.notify.send_email') - def test_api_pull_request_add_flag_user_token(self, mockemail): - """ Test the api_pull_request_add_flag method of the flask api. """ - mockemail.return_value = True - - tests.create_projects(self.session) - tests.create_tokens(self.session, project_id=None) - tests.create_tokens_acl(self.session) - - headers = {'Authorization': 'token aaabbbcccddd'} - - # Invalid project - output = self.app.post( - '/api/0/foo/pull-request/1/flag', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Project not found", - "error_code": "ENOPROJECT", - } - ) - - # Valid token, wrong project - output = self.app.post( - '/api/0/test2/pull-request/1/flag', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Pull-Request not found", - "error_code": "ENOREQ", - } - ) - - # No input - output = self.app.post( - '/api/0/test/pull-request/1/flag', headers=headers) - self.assertEqual(output.status_code, 404) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Pull-Request not found", - "error_code": "ENOREQ", - } - ) - - # Create a pull-request - repo = pagure.lib.get_authorized_project(self.session, 'test') - forked_repo = pagure.lib.get_authorized_project(self.session, 'test') - req = pagure.lib.new_pull_request( - session=self.session, - repo_from=forked_repo, - branch_from='master', - repo_to=repo, - branch_to='master', - title='test pull-request', - user='pingou', - requestfolder=None, - ) - self.session.commit() - self.assertEqual(req.id, 1) - self.assertEqual(req.title, 'test pull-request') - - # Check comments before - self.session = pagure.lib.create_session(self.dbpath) - request = pagure.lib.search_pull_requests( - self.session, project_id=1, requestid=1) - self.assertEqual(len(request.flags), 0) - - data = { - 'username': 'Jenkins', - 'percent': 100, - 'url': 'http://jenkins.cloud.fedoraproject.org/', - 'uid': 'jenkins_build_pagure_100+seed', - } - - # Incomplete request - output = self.app.post( - '/api/0/test/pull-request/1/flag', data=data, headers=headers) - self.assertEqual(output.status_code, 400) - data = json.loads(output.data) - self.assertDictEqual( - data, - { - "error": "Invalid or incomplete input submitted", - "error_code": "EINVALIDREQ", - "errors": {"comment": ["This field is required."]} - } - ) - - # No change - self.session = pagure.lib.create_session(self.dbpath) - request = pagure.lib.search_pull_requests( - self.session, project_id=1, requestid=1) - self.assertEqual(len(request.flags), 0) - - data = { - 'username': 'Jenkins', - 'percent': 0, - 'comment': 'Tests failed', - 'url': 'http://jenkins.cloud.fedoraproject.org/', - 'uid': 'jenkins_build_pagure_100+seed', - } - - # Valid request - w/o providing the status - output = self.app.post( - '/api/0/test/pull-request/1/flag', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - data['flag']['date_created'] = u'1510742565' - data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' - self.assertDictEqual( - data, - { - u'flag': { - u'comment': u'Tests failed', - u'date_created': u'1510742565', - u'percent': 0, - u'pull_request_uid': u'62b49f00d489452994de5010565fab81', - u'status': u'failure', - u'url': u'http://jenkins.cloud.fedoraproject.org/', - u'user': { - u'default_email': u'bar@pingou.com', - u'emails': [u'bar@pingou.com', u'foo@pingou.com'], - u'fullname': u'PY C', - u'name': u'pingou'}, - u'username': u'Jenkins'}, - u'message': u'Flag added', - u'uid': u'jenkins_build_pagure_100+seed' - } - ) - - # One flag added - self.session = pagure.lib.create_session(self.dbpath) - request = pagure.lib.search_pull_requests( - self.session, project_id=1, requestid=1) - self.assertEqual(len(request.flags), 1) - self.assertEqual(request.flags[0].comment, 'Tests failed') - self.assertEqual(request.flags[0].percent, 0) - - # Update flag - data = { - 'username': 'Jenkins', - 'percent': 100, - 'comment': 'Tests passed', - 'url': 'http://jenkins.cloud.fedoraproject.org/', - 'uid': 'jenkins_build_pagure_100+seed', - 'status': 'success', - } - - output = self.app.post( - '/api/0/test/pull-request/1/flag', data=data, headers=headers) - self.assertEqual(output.status_code, 200) - data = json.loads(output.data) - data['flag']['date_created'] = u'1510742565' - data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' - self.assertDictEqual( - data, - { - u'flag': { - u'comment': u'Tests passed', - u'date_created': u'1510742565', - u'percent': 100, - u'pull_request_uid': u'62b49f00d489452994de5010565fab81', - u'status': u'success', - u'url': u'http://jenkins.cloud.fedoraproject.org/', - u'user': { - u'default_email': u'bar@pingou.com', - u'emails': [u'bar@pingou.com', u'foo@pingou.com'], - u'fullname': u'PY C', - u'name': u'pingou'}, - u'username': u'Jenkins'}, - u'message': u'Flag updated', - u'uid': u'jenkins_build_pagure_100+seed' - } - ) - - # One flag added - self.session = pagure.lib.create_session(self.dbpath) - request = pagure.lib.search_pull_requests( - self.session, project_id=1, requestid=1) - self.assertEqual(len(request.flags), 1) - self.assertEqual(request.flags[0].comment, 'Tests passed') - self.assertEqual(request.flags[0].percent, 100) - @patch('pagure.lib.git.update_git') @patch('pagure.lib.notify.send_email') def test_api_subscribe_pull_request(self, p_send_email, p_ugt): diff --git a/tests/test_pagure_flask_api_pr_flag.py b/tests/test_pagure_flask_api_pr_flag.py new file mode 100644 index 0000000..d711e8e --- /dev/null +++ b/tests/test_pagure_flask_api_pr_flag.py @@ -0,0 +1,744 @@ +# -*- coding: utf-8 -*- + +""" + (c) 2018 - Copyright Red Hat Inc + + Authors: + Pierre-Yves Chibon + +""" + +import unittest +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__)), '..')) + +import pagure # noqa +import pagure.lib # noqa +import tests # noqa + + +class PagureFlaskApiPRFlagtests(tests.Modeltests): + """ Tests for the flask API of pagure for flagging pull-requests """ + + maxDiff = None + + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureFlaskApiPRFlagtests, self).setUp() + + pagure.config.config['REQUESTS_FOLDER'] = None + + tests.create_projects(self.session) + tests.create_tokens(self.session) + tests.create_tokens_acl(self.session) + + # Create a pull-request + repo = pagure.lib.get_authorized_project(self.session, 'test') + forked_repo = pagure.lib.get_authorized_project(self.session, 'test') + req = pagure.lib.new_pull_request( + session=self.session, + repo_from=forked_repo, + branch_from='master', + repo_to=repo, + branch_to='master', + title='test pull-request', + user='pingou', + requestfolder=None, + ) + self.session.commit() + self.assertEqual(req.id, 1) + self.assertEqual(req.title, 'test pull-request') + + # Check flags before + # self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 0) + + def test_invalid_project(self): + """ Test the flagging a PR on an invalid project. """ + + headers = {'Authorization': 'token aaabbbcccddd'} + + # Invalid project + output = self.app.post( + '/api/0/foo/pull-request/1/flag', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Project not found", + "error_code": "ENOPROJECT", + } + ) + + def test_incorrect_project(self): + """ Test the flagging a PR on the wrong project. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + # Valid token, wrong project + output = self.app.post( + '/api/0/test2/pull-request/1/flag', headers=headers) + self.assertEqual(output.status_code, 401) + data = json.loads(output.data) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.name, + data['error_code']) + self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data['error']) + + def test_no_pr(self): + """ Test the flagging a PR when the PR doesn't exist. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + # No PR + output = self.app.post( + '/api/0/test/pull-request/10/flag', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Pull-Request not found", + "error_code": "ENOREQ", + } + ) + + def test_no_input(self): + """ Test the flagging an existing PR but with no data. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + # No input + output = self.app.post( + '/api/0/test/pull-request/1/flag', headers=headers) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + u'error': u'Invalid or incomplete input submitted', + u'error_code': u'EINVALIDREQ', + u'errors': { + u'comment': [u'This field is required.'], + u'url': [u'This field is required.'], + u'username': [u'This field is required.'] + } + } + ) + + def test_no_comment(self): + """ Test the flagging an existing PR but with incomplete data. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'username': 'Jenkins', + 'percent': 100, + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Incomplete request + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Invalid or incomplete input submitted", + "error_code": "EINVALIDREQ", + "errors": {"comment": ["This field is required."]} + } + ) + + # No change + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 0) + + @patch('pagure.lib.notify.send_email') + def test_flagging_a_pul_request_with_notification(self, mock_email): + """ Test the flagging a PR. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + # Enable PR notifications + repo = pagure.lib.get_authorized_project(self.session, 'test') + settings = repo.settings + settings['notify_on_pull-request_flag'] = True + repo.settings = settings + self.session.add(repo) + self.session.commit() + + data = { + 'username': 'Jenkins', + 'comment': 'Tests running', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Valid request + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + data['flag']['date_created'] = u'1510742565' + pr_uid = data['flag']['pull_request_uid'] + data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' + self.assertDictEqual( + data, + { + u'flag': { + u'comment': u'Tests running', + u'date_created': u'1510742565', + u'percent': None, + u'pull_request_uid': u'62b49f00d489452994de5010565fab81', + u'status': u'pending', + u'url': u'http://jenkins.cloud.fedoraproject.org/', + u'user': { + u'default_email': u'bar@pingou.com', + u'emails': [u'bar@pingou.com', u'foo@pingou.com'], + u'fullname': u'PY C', + u'name': u'pingou' + }, + u'username': u'Jenkins'}, + u'message': u'Flag added', + u'uid': u'jenkins_build_pagure_100+seed' + } + ) + + # One flag added + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 1) + self.assertEqual(request.flags[0].comment, 'Tests running') + self.assertEqual(request.flags[0].percent, None) + + # Check the notification sent + mock_email.assert_called_once_with( + u'\nJenkins flagged the pull-request `test pull-request` ' + u'as pending: Tests running\n\n' + u'https://pagure.org/test/pull-request/1\n', + u'PR #1 - Jenkins: pending', + u'bar@pingou.com', + in_reply_to=u'test-pull-request-' + pr_uid, + mail_id=u'test-pull-request-' + pr_uid + '-1', + project_name=u'test', + user_from=u'Jenkins' + ) + + def test_updating_flag(self): + """ Test the updating the flag of a PR. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'username': 'Jenkins', + 'comment': 'Tests running', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Valid request + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + data['flag']['date_created'] = u'1510742565' + data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' + self.assertDictEqual( + data, + { + u'flag': { + u'comment': u'Tests running', + u'date_created': u'1510742565', + u'percent': None, + u'pull_request_uid': u'62b49f00d489452994de5010565fab81', + u'status': u'pending', + u'url': u'http://jenkins.cloud.fedoraproject.org/', + u'user': { + u'default_email': u'bar@pingou.com', + u'emails': [u'bar@pingou.com', u'foo@pingou.com'], + u'fullname': u'PY C', + u'name': u'pingou' + }, + u'username': u'Jenkins'}, + u'message': u'Flag added', + u'uid': u'jenkins_build_pagure_100+seed' + } + ) + + # One flag added + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 1) + self.assertEqual(request.flags[0].comment, 'Tests running') + self.assertEqual(request.flags[0].percent, None) + + # Update flag - w/o providing the status + data = { + 'username': 'Jenkins', + 'percent': 100, + 'comment': 'Tests passed', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + data['flag']['date_created'] = u'1510742565' + data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' + self.assertDictEqual( + data, + { + u'flag': { + u'comment': u'Tests passed', + u'date_created': u'1510742565', + u'percent': 100, + u'pull_request_uid': u'62b49f00d489452994de5010565fab81', + u'status': u'success', + u'url': u'http://jenkins.cloud.fedoraproject.org/', + u'user': { + u'default_email': u'bar@pingou.com', + u'emails': [u'bar@pingou.com', u'foo@pingou.com'], + u'fullname': u'PY C', + u'name': u'pingou' + }, + u'username': u'Jenkins'}, + u'message': u'Flag updated', + u'uid': u'jenkins_build_pagure_100+seed' + } + ) + + # One flag added + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 1) + self.assertEqual(request.flags[0].comment, 'Tests passed') + self.assertEqual(request.flags[0].percent, 100) + + def test_adding_two_flags(self): + """ Test the adding two flags to a PR. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'username': 'Jenkins', + 'comment': 'Tests passed', + 'status': 'success', + 'percent': '100', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Valid request + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + data['flag']['date_created'] = u'1510742565' + data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' + self.assertDictEqual( + data, + { + u'flag': { + u'comment': u'Tests passed', + u'date_created': u'1510742565', + u'percent': 100, + u'pull_request_uid': u'62b49f00d489452994de5010565fab81', + u'status': u'success', + u'url': u'http://jenkins.cloud.fedoraproject.org/', + u'user': { + u'default_email': u'bar@pingou.com', + u'emails': [u'bar@pingou.com', u'foo@pingou.com'], + u'fullname': u'PY C', + u'name': u'pingou' + }, + u'username': u'Jenkins'}, + u'message': u'Flag added', + u'uid': u'jenkins_build_pagure_100+seed' + } + ) + + # One flag added + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 1) + self.assertEqual(request.flags[0].comment, 'Tests passed') + self.assertEqual(request.flags[0].percent, 100) + + data = { + 'username': 'Jenkins', + 'comment': 'Tests running again', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + } + + # Valid request + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + data['flag']['date_created'] = u'1510742565' + data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' + self.assertNotEqual( + data['uid'], 'jenkins_build_pagure_100+seed') + data['uid'] = 'jenkins_build_pagure_100+seed' + self.assertDictEqual( + data, + { + u'flag': { + u'comment': u'Tests running again', + u'date_created': u'1510742565', + u'percent': None, + u'pull_request_uid': u'62b49f00d489452994de5010565fab81', + u'status': u'pending', + u'url': u'http://jenkins.cloud.fedoraproject.org/', + u'user': { + u'default_email': u'bar@pingou.com', + u'emails': [u'bar@pingou.com', u'foo@pingou.com'], + u'fullname': u'PY C', + u'name': u'pingou' + }, + u'username': u'Jenkins'}, + u'message': u'Flag added', + u'uid': u'jenkins_build_pagure_100+seed' + } + ) + + # Two flag added + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 2) + self.assertEqual(request.flags[0].comment, 'Tests passed') + self.assertEqual(request.flags[0].percent, 100) + self.assertEqual(request.flags[1].comment, 'Tests running again') + self.assertEqual(request.flags[1].percent, None) + + +class PagureFlaskApiPRFlagUserTokentests(tests.Modeltests): + """ Tests for the flask API of pagure for flagging pull-requests using + an user token (ie: not restricted to a specific project). + """ + + maxDiff = None + + @patch('pagure.lib.notify.send_email', MagicMock(return_value=True)) + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureFlaskApiPRFlagUserTokentests, self).setUp() + + pagure.config.config['REQUESTS_FOLDER'] = None + + tests.create_projects(self.session) + tests.create_tokens(self.session, project_id=None) + tests.create_tokens_acl(self.session) + + # Create a pull-request + repo = pagure.lib.get_authorized_project(self.session, 'test') + forked_repo = pagure.lib.get_authorized_project(self.session, 'test') + req = pagure.lib.new_pull_request( + session=self.session, + repo_from=forked_repo, + branch_from='master', + repo_to=repo, + branch_to='master', + title='test pull-request', + user='pingou', + requestfolder=None, + ) + self.session.commit() + self.assertEqual(req.id, 1) + self.assertEqual(req.title, 'test pull-request') + + # Check flags before + # self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 0) + + def test_no_pr(self): + """ Test flagging a non-existing PR. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + # Invalid project + output = self.app.post( + '/api/0/foo/pull-request/1/flag', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Project not found", + "error_code": "ENOPROJECT", + } + ) + + def test_no_pr_other_project(self): + """ Test flagging a non-existing PR on a different project. """ + headers = {'Authorization': 'token aaabbbcccddd'} + # Valid token, wrong project + output = self.app.post( + '/api/0/test2/pull-request/1/flag', headers=headers) + self.assertEqual(output.status_code, 404) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Pull-Request not found", + "error_code": "ENOREQ", + } + ) + + def test_no_input(self): + """ Test flagging an existing PR but without submitting any data. """ + headers = {'Authorization': 'token aaabbbcccddd'} + + # No input + output = self.app.post( + '/api/0/test/pull-request/1/flag', headers=headers) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + u'error': u'Invalid or incomplete input submitted', + u'error_code': u'EINVALIDREQ', + u'errors': { + u'comment': [u'This field is required.'], + u'url': [u'This field is required.'], + u'username': [u'This field is required.'] + } + } + ) + + def test_no_comment(self): + """ Test flagging an existing PR but without all the required info. + """ + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'username': 'Jenkins', + 'percent': 100, + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Incomplete request + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Invalid or incomplete input submitted", + "error_code": "EINVALIDREQ", + "errors": {"comment": ["This field is required."]} + } + ) + + # No change + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 0) + + def test_invalid_status(self): + """ Test flagging an existing PR but with an invalid status. + """ + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'username': 'Jenkins', + 'status': 'failed', + 'comment': 'Failed to run the tests', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Invalid status submitted + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 400) + data = json.loads(output.data) + self.assertDictEqual( + data, + { + "error": "Invalid or incomplete input submitted", + "error_code": "EINVALIDREQ", + "errors": {"status": ["Not a valid choice"]} + } + ) + + # No change + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 0) + + @patch('pagure.lib.notify.send_email') + def test_flag_pr_no_status(self, mock_email): + """ Test flagging an existing PR without providing a status. + + Also check that no notifications have been sent. + """ + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'username': 'Jenkins', + 'percent': 0, + 'comment': 'Tests failed', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Valid request - w/o providing the status + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + data['flag']['date_created'] = u'1510742565' + data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' + self.assertDictEqual( + data, + { + u'flag': { + u'comment': u'Tests failed', + u'date_created': u'1510742565', + u'percent': 0, + u'pull_request_uid': u'62b49f00d489452994de5010565fab81', + u'status': u'failure', + u'url': u'http://jenkins.cloud.fedoraproject.org/', + u'user': { + u'default_email': u'bar@pingou.com', + u'emails': [u'bar@pingou.com', u'foo@pingou.com'], + u'fullname': u'PY C', + u'name': u'pingou' + }, + u'username': u'Jenkins'}, + u'message': u'Flag added', + u'uid': u'jenkins_build_pagure_100+seed' + } + ) + + # One flag added + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 1) + self.assertEqual(request.flags[0].comment, 'Tests failed') + self.assertEqual(request.flags[0].percent, 0) + + # no notifications sent + mock_email.assert_not_called() + + def test_editing_flag(self): + """ Test flagging an existing PR without providing a status. + """ + headers = {'Authorization': 'token aaabbbcccddd'} + + data = { + 'username': 'Jenkins', + 'status': 'failure', + 'comment': 'Tests failed', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + } + + # Valid request - w/o providing the status + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + data['flag']['date_created'] = u'1510742565' + data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' + self.assertDictEqual( + data, + { + u'flag': { + u'comment': u'Tests failed', + u'date_created': u'1510742565', + u'percent': None, + u'pull_request_uid': u'62b49f00d489452994de5010565fab81', + u'status': u'failure', + u'url': u'http://jenkins.cloud.fedoraproject.org/', + u'user': { + u'default_email': u'bar@pingou.com', + u'emails': [u'bar@pingou.com', u'foo@pingou.com'], + u'fullname': u'PY C', + u'name': u'pingou' + }, + u'username': u'Jenkins'}, + u'message': u'Flag added', + u'uid': u'jenkins_build_pagure_100+seed' + } + ) + + # One flag added + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 1) + self.assertEqual(request.flags[0].comment, 'Tests failed') + self.assertEqual(request.flags[0].percent, None) + + # Update flag + data = { + 'username': 'Jenkins', + 'percent': 100, + 'comment': 'Tests passed', + 'url': 'http://jenkins.cloud.fedoraproject.org/', + 'uid': 'jenkins_build_pagure_100+seed', + 'status': 'success', + } + + output = self.app.post( + '/api/0/test/pull-request/1/flag', data=data, headers=headers) + self.assertEqual(output.status_code, 200) + data = json.loads(output.data) + data['flag']['date_created'] = u'1510742565' + data['flag']['pull_request_uid'] = u'62b49f00d489452994de5010565fab81' + self.assertDictEqual( + data, + { + u'flag': { + u'comment': u'Tests passed', + u'date_created': u'1510742565', + u'percent': 100, + u'pull_request_uid': u'62b49f00d489452994de5010565fab81', + u'status': u'success', + u'url': u'http://jenkins.cloud.fedoraproject.org/', + u'user': { + u'default_email': u'bar@pingou.com', + u'emails': [u'bar@pingou.com', u'foo@pingou.com'], + u'fullname': u'PY C', + u'name': u'pingou' + }, + u'username': u'Jenkins'}, + u'message': u'Flag updated', + u'uid': u'jenkins_build_pagure_100+seed' + } + ) + + # Still only one flag + self.session = pagure.lib.create_session(self.dbpath) + request = pagure.lib.search_pull_requests( + self.session, project_id=1, requestid=1) + self.assertEqual(len(request.flags), 1) + self.assertEqual(request.flags[0].comment, 'Tests passed') + self.assertEqual(request.flags[0].percent, 100) + + +if __name__ == '__main__': + unittest.main(verbosity=2)