# -*- coding: utf-8 -*- """ (c) 2019 - Copyright Red Hat Inc Authors: Pierre-Yves Chibon """ from __future__ import unicode_literals, absolute_import import arrow import copy import datetime import unittest import shutil import sys import time import os import flask import json import munch from mock import patch, MagicMock from sqlalchemy.exc import SQLAlchemyError sys.path.insert( 0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") ) import pagure.lib.query import tests class PagureFlaskApiForkUpdatetests(tests.SimplePagureTest): """ Tests for the flask API of pagure for updating a PR """ maxDiff = None @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, ran before every tests. """ super(PagureFlaskApiForkUpdatetests, self).setUp() tests.create_projects(self.session) tests.add_content_git_repo( os.path.join(self.path, "repos", "test.git") ) # Fork project = pagure.lib.query.get_authorized_project(self.session, "test") task = pagure.lib.query.fork_project( session=self.session, user="pingou", repo=project ) self.session.commit() self.assertEqual( task.get(), { "endpoint": "ui_ns.view_repo", "repo": "test", "namespace": None, "username": "pingou", }, ) tests.add_readme_git_repo( os.path.join(self.path, "repos", "forks", "pingou", "test.git") ) project = pagure.lib.query.get_authorized_project(self.session, "test") fork = pagure.lib.query.get_authorized_project( self.session, "test", user="pingou" ) tests.create_tokens(self.session) tests.create_tokens_acl(self.session) req = pagure.lib.query.new_pull_request( session=self.session, repo_from=fork, branch_from="master", repo_to=project, branch_to="master", title="test pull-request", user="pingou", ) self.session.commit() self.assertEqual(req.id, 1) self.assertEqual(req.title, "test pull-request") # Assert the PR is open self.session = pagure.lib.query.create_session(self.dbpath) project = pagure.lib.query.get_authorized_project(self.session, "test") self.assertEqual(len(project.requests), 1) self.assertEqual(project.requests[0].status, "Open") # Check how the PR renders in the API and the UI output = self.app.get("/api/0/test/pull-request/1") self.assertEqual(output.status_code, 200) output = self.app.get("/test/pull-request/1") self.assertEqual(output.status_code, 200) def test_api_pull_request_update_invalid_project_namespace(self): """ Test api_pull_request_update method when the project doesn't exist. """ headers = {"Authorization": "token aaabbbcccddd"} # Valid token, wrong project output = self.app.post( "/api/0/somenamespace/test3/pull-request/1", headers=headers ) self.assertEqual(output.status_code, 401) data = json.loads(output.get_data(as_text=True)) self.assertDictEqual( data, { "error": "Invalid or expired token. Please visit " "http://localhost.localdomain/settings#nav-api-tab to get or renew your " "API token.", "error_code": "EINVALIDTOK", }, ) def test_api_pull_request_update_invalid_project(self): """ Test api_pull_request_update method when the project doesn't exist. """ headers = {"Authorization": "token aaabbbcccddd"} # Invalid project output = self.app.post("/api/0/foo/pull-request/1", headers=headers) self.assertEqual(output.status_code, 404) data = json.loads(output.get_data(as_text=True)) self.assertDictEqual( data, {"error": "Project not found", "error_code": "ENOPROJECT"} ) def test_api_pull_request_update_invalid_project_token(self): """ Test api_pull_request_update method when the token doesn't correspond to the project. """ headers = {"Authorization": "token aaabbbcccddd"} # Valid token, wrong project output = self.app.post("/api/0/test2/pull-request/1", 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"]) self.assertEqual(pagure.api.APIERROR.EINVALIDTOK.value, data["error"]) self.assertEqual( pagure.api.APIERROR.EINVALIDTOK.name, data["error_code"] ) def test_api_pull_request_update_invalid_pr(self): """ Test api_assign_pull_request method when asking for an invalid PR """ headers = {"Authorization": "token aaabbbcccddd"} # Invalid PR id output = self.app.post("/api/0/test/pull-request/404", headers=headers) self.assertEqual(output.status_code, 404) data = json.loads(output.get_data(as_text=True)) self.assertDictEqual( data, {"error": "Pull-Request not found", "error_code": "ENOREQ"} ) def test_api_pull_request_update_no_input(self): """ Test api_assign_pull_request method when no input is specified """ headers = {"Authorization": "token aaabbbcccddd"} # No input output = self.app.post("/api/0/test/pull-request/1", headers=headers) self.assertEqual(output.status_code, 400) data = json.loads(output.get_data(as_text=True)) self.assertDictEqual( data, { "error": "Invalid or incomplete input submitted", "error_code": "EINVALIDREQ", "errors": {"title": ["This field is required."]}, }, ) def test_api_pull_request_update_insufficient_input(self): """ Test api_assign_pull_request method when no input is specified """ headers = {"Authorization": "token aaabbbcccddd"} data = {"initial_comment": "will not work"} # Missing the required title field output = self.app.post( "/api/0/test/pull-request/1", data=data, headers=headers ) self.assertEqual(output.status_code, 400) data = json.loads(output.get_data(as_text=True)) self.assertDictEqual( data, { "error": "Invalid or incomplete input submitted", "error_code": "EINVALIDREQ", "errors": {"title": ["This field is required."]}, }, ) def test_api_pull_request_update_edited(self): """ Test api_assign_pull_request method when with valid input """ headers = {"Authorization": "token aaabbbcccddd"} data = { "title": "edited test PR", "initial_comment": "Edited initial comment", } # Valid request output = self.app.post( "/api/0/test/pull-request/1", data=data, headers=headers ) self.assertEqual(output.status_code, 200) data = json.loads(output.get_data(as_text=True)) # Hard-code all the values that will change from a test to another # because either random or time-based data["date_created"] = "1551276260" data["last_updated"] = "1551276261" data["updated_on"] = "1551276260" data["commit_start"] = "5f5d609db65d447f77ba00e25afd17ba5053344b" data["commit_stop"] = "5f5d609db65d447f77ba00e25afd17ba5053344b" data["project"]["date_created"] = "1551276259" data["project"]["date_modified"] = "1551276259" data["repo_from"]["date_created"] = "1551276259" data["repo_from"]["date_modified"] = "1551276259" data["repo_from"]["parent"]["date_created"] = "1551276259" data["repo_from"]["parent"]["date_modified"] = "1551276259" data["uid"] = "a2bddecc8ea548e88c22a0df77670092" self.assertDictEqual( data, { "assignee": None, "branch": "master", "branch_from": "master", "cached_merge_status": "unknown", "closed_at": None, "closed_by": None, "comments": [], "commit_start": "5f5d609db65d447f77ba00e25afd17ba5053344b", "commit_stop": "5f5d609db65d447f77ba00e25afd17ba5053344b", "date_created": "1551276260", "id": 1, "initial_comment": "Edited initial comment", "last_updated": "1551276261", "project": { "access_groups": { "admin": [], "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], }, "close_status": [ "Invalid", "Insufficient data", "Fixed", "Duplicate", ], "custom_keys": [], "date_created": "1551276259", "date_modified": "1551276259", "description": "test project #1", "fullname": "test", "id": 1, "milestones": {}, "name": "test", "namespace": None, "parent": None, "priorities": {}, "tags": [], "url_path": "test", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, "remote_git": None, "repo_from": { "access_groups": { "admin": [], "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], }, "close_status": [], "custom_keys": [], "date_created": "1551276259", "date_modified": "1551276259", "description": "test project #1", "fullname": "forks/pingou/test", "id": 4, "milestones": {}, "name": "test", "namespace": None, "parent": { "access_groups": { "admin": [], "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], }, "close_status": [ "Invalid", "Insufficient data", "Fixed", "Duplicate", ], "custom_keys": [], "date_created": "1551276259", "date_modified": "1551276259", "description": "test project #1", "fullname": "test", "id": 1, "milestones": {}, "name": "test", "namespace": None, "parent": None, "priorities": {}, "tags": [], "url_path": "test", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, "priorities": {}, "tags": [], "url_path": "fork/pingou/test", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, "status": "Open", "tags": [], "threshold_reached": None, "title": "edited test PR", "uid": "a2bddecc8ea548e88c22a0df77670092", "updated_on": "1551276260", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, ) def test_api_pull_request_update_edited_no_comment(self): """ Test api_assign_pull_request method when with valid input """ headers = {"Authorization": "token aaabbbcccddd"} data = {"title": "edited test PR"} # Valid request output = self.app.post( "/api/0/test/pull-request/1", data=data, headers=headers ) self.assertEqual(output.status_code, 200) data = json.loads(output.get_data(as_text=True)) # Hard-code all the values that will change from a test to another # because either random or time-based data["date_created"] = "1551276260" data["last_updated"] = "1551276261" data["updated_on"] = "1551276260" data["commit_start"] = "5f5d609db65d447f77ba00e25afd17ba5053344b" data["commit_stop"] = "5f5d609db65d447f77ba00e25afd17ba5053344b" data["project"]["date_created"] = "1551276259" data["project"]["date_modified"] = "1551276259" data["repo_from"]["date_created"] = "1551276259" data["repo_from"]["date_modified"] = "1551276259" data["repo_from"]["parent"]["date_created"] = "1551276259" data["repo_from"]["parent"]["date_modified"] = "1551276259" data["uid"] = "a2bddecc8ea548e88c22a0df77670092" self.assertDictEqual( data, { "assignee": None, "branch": "master", "branch_from": "master", "cached_merge_status": "unknown", "closed_at": None, "closed_by": None, "comments": [], "commit_start": "5f5d609db65d447f77ba00e25afd17ba5053344b", "commit_stop": "5f5d609db65d447f77ba00e25afd17ba5053344b", "date_created": "1551276260", "id": 1, "initial_comment": "", "last_updated": "1551276261", "project": { "access_groups": { "admin": [], "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], }, "close_status": [ "Invalid", "Insufficient data", "Fixed", "Duplicate", ], "custom_keys": [], "date_created": "1551276259", "date_modified": "1551276259", "description": "test project #1", "fullname": "test", "id": 1, "milestones": {}, "name": "test", "namespace": None, "parent": None, "priorities": {}, "tags": [], "url_path": "test", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, "remote_git": None, "repo_from": { "access_groups": { "admin": [], "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], }, "close_status": [], "custom_keys": [], "date_created": "1551276259", "date_modified": "1551276259", "description": "test project #1", "fullname": "forks/pingou/test", "id": 4, "milestones": {}, "name": "test", "namespace": None, "parent": { "access_groups": { "admin": [], "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], }, "close_status": [ "Invalid", "Insufficient data", "Fixed", "Duplicate", ], "custom_keys": [], "date_created": "1551276259", "date_modified": "1551276259", "description": "test project #1", "fullname": "test", "id": 1, "milestones": {}, "name": "test", "namespace": None, "parent": None, "priorities": {}, "tags": [], "url_path": "test", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, "priorities": {}, "tags": [], "url_path": "fork/pingou/test", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, "status": "Open", "tags": [], "threshold_reached": None, "title": "edited test PR", "uid": "a2bddecc8ea548e88c22a0df77670092", "updated_on": "1551276260", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, ) def test_api_pull_request_update_edited_linked(self): """ Test api_assign_pull_request method when with valid input """ project = pagure.lib.query.get_authorized_project(self.session, "test") self.assertEqual(len(project.requests), 1) self.assertEqual(len(project.requests[0].related_issues), 0) self.assertEqual(len(project.issues), 0) # Create issues to link to msg = pagure.lib.query.new_issue( session=self.session, repo=project, title="tést íssüé", content="We should work on this", user="pingou", ) self.session.commit() self.assertEqual(msg.title, "tést íssüé") headers = {"Authorization": "token aaabbbcccddd"} data = { "title": "edited test PR", "initial_comment": "Edited initial comment\n\n" "this PR fixes #2 \n\nThanks", } # Valid request output = self.app.post( "/api/0/test/pull-request/1", data=data, headers=headers ) self.assertEqual(output.status_code, 200) data = json.loads(output.get_data(as_text=True)) # Hard-code all the values that will change from a test to another # because either random or time-based data["date_created"] = "1551276260" data["last_updated"] = "1551276261" data["updated_on"] = "1551276260" data["commit_start"] = "5f5d609db65d447f77ba00e25afd17ba5053344b" data["commit_stop"] = "5f5d609db65d447f77ba00e25afd17ba5053344b" data["project"]["date_created"] = "1551276259" data["project"]["date_modified"] = "1551276259" data["repo_from"]["date_created"] = "1551276259" data["repo_from"]["date_modified"] = "1551276259" data["repo_from"]["parent"]["date_created"] = "1551276259" data["repo_from"]["parent"]["date_modified"] = "1551276259" data["uid"] = "a2bddecc8ea548e88c22a0df77670092" self.assertDictEqual( data, { "assignee": None, "branch": "master", "branch_from": "master", "cached_merge_status": "unknown", "closed_at": None, "closed_by": None, "comments": [], "commit_start": "5f5d609db65d447f77ba00e25afd17ba5053344b", "commit_stop": "5f5d609db65d447f77ba00e25afd17ba5053344b", "date_created": "1551276260", "id": 1, "initial_comment": "Edited initial comment\n\nthis PR " "fixes #2 \n\nThanks", "last_updated": "1551276261", "project": { "access_groups": { "admin": [], "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], }, "close_status": [ "Invalid", "Insufficient data", "Fixed", "Duplicate", ], "custom_keys": [], "date_created": "1551276259", "date_modified": "1551276259", "description": "test project #1", "fullname": "test", "id": 1, "milestones": {}, "name": "test", "namespace": None, "parent": None, "priorities": {}, "tags": [], "url_path": "test", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, "remote_git": None, "repo_from": { "access_groups": { "admin": [], "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], }, "close_status": [], "custom_keys": [], "date_created": "1551276259", "date_modified": "1551276259", "description": "test project #1", "fullname": "forks/pingou/test", "id": 4, "milestones": {}, "name": "test", "namespace": None, "parent": { "access_groups": { "admin": [], "collaborator": [], "commit": [], "ticket": [], }, "access_users": { "admin": [], "collaborator": [], "commit": [], "owner": ["pingou"], "ticket": [], }, "close_status": [ "Invalid", "Insufficient data", "Fixed", "Duplicate", ], "custom_keys": [], "date_created": "1551276259", "date_modified": "1551276259", "description": "test project #1", "fullname": "test", "id": 1, "milestones": {}, "name": "test", "namespace": None, "parent": None, "priorities": {}, "tags": [], "url_path": "test", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, "priorities": {}, "tags": [], "url_path": "fork/pingou/test", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, "status": "Open", "tags": [], "threshold_reached": None, "title": "edited test PR", "uid": "a2bddecc8ea548e88c22a0df77670092", "updated_on": "1551276260", "user": { "fullname": "PY C", "name": "pingou", "url_path": "user/pingou", }, }, ) project = pagure.lib.query.get_authorized_project(self.session, "test") self.assertEqual(len(project.requests), 1) self.assertEqual(len(project.requests[0].related_issues), 1) self.assertEqual(len(project.issues), 1) self.assertEqual(len(project.issues[0].related_prs), 1) if __name__ == "__main__": unittest.main(verbosity=2)