gitea-redmine/test_app.py

491 lines
16 KiB
Python

import pytest
import gitea_redmine
@pytest.fixture
def client():
return gitea_redmine.app.test_client()
@pytest.mark.parametrize(
'payload, expected_handler, expected_event',
[
(
{'action': 'opened', 'pull_request': {'title': 'foo'}},
gitea_redmine.handle_pull_request_opened,
'pull_request.opened',
),
(
{'action': 'opened', 'pull_request': {'title': 'WIP: foo'}},
gitea_redmine.handle_pull_request_opened_draft,
'pull_request.opened',
),
(
{'action': 'edited', 'pull_request': {'title': 'foo'}},
gitea_redmine.handle_pull_request_edited,
'pull_request.edited',
),
(
{'action': 'edited', 'pull_request': {'title': 'WIP: something'}},
gitea_redmine.handle_pull_request_draft,
'pull_request.draft',
),
(
{'action': 'reviewed', 'review': {"type": "pull_request_review_approved"}},
gitea_redmine.handle_pull_request_approved,
'pull_request.approved',
),
(
{'action': 'reviewed', 'review': {"type": "pull_request_review_rejected"}},
gitea_redmine.handle_pull_request_rejected,
'pull_request.rejected',
),
(
{'action': 'closed', 'pull_request': {'merged': True}},
gitea_redmine.handle_pull_request_merged,
'pull_request.merged',
),
({'action': 'unknown', 'pull_request': 'foo'}, None, None),
],
)
def test_get_handler(payload, expected_handler, expected_event):
assert gitea_redmine.get_handler(payload) == (expected_handler, expected_event)
@pytest.mark.parametrize(
'text, branch_name, expected',
[
('None', '', []),
('#1, #2', '', [1, 2]),
('#none, #2', '', [2]),
('# Header\n, #2', '', [2]),
('# Header', 'wip/2-something', [2]),
('# Header', 'wip/2', [2]),
('# Header', 'wip/noop-2', []),
('#2 #3', 'wip/noop-2', [2, 3]),
],
)
def test_get_issues_ids(text, branch_name, expected):
assert gitea_redmine.get_issues_ids(text, branch_name) == expected
@pytest.mark.parametrize(
'dict, expected',
[
({'a': 'foo', 'b': 'bar'}, {'a': 'foo', 'b': 'bar'}),
({'a': {'b': 'bar'}}, {'a_b': 'bar'}),
],
)
def test_flatten(dict, expected):
assert gitea_redmine.flatten(dict) == expected
def test_handle_pull_request_opened(mocker):
redmine_user = mocker.Mock(id=42)
get_redmine_user = mocker.patch.object(gitea_redmine, 'get_redmine_user', return_value=redmine_user)
payload = {
"action": "opened",
"number": 2,
"pull_request": {
"id": 7,
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
"number": 2,
"user": {
"id": 7,
"login": "testuser",
"full_name": "Test User",
"email": "test_user@noreply.gitea.entrouvert.org",
"username": "testuser",
},
"title": "Foo",
"body": "See #70893",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock()
gitea_redmine.handle_pull_request_opened(issue, payload, project)
get_redmine_user.assert_called_once_with('testuser')
assert issue.assigned_to_id == redmine_user.id
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['Solution proposée']
assert issue.notes == (
'Test User (testuser) a ouvert une pull request sur Gitea concernant cette demande :\n\n'
'* URL : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2\n'
'* Titre : Foo\n'
'* Modifications : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2/files'
)
issue.save.assert_called_once()
@pytest.mark.parametrize(
'status',
[
gitea_redmine.REDMINE_STATUSES['Résolu'],
gitea_redmine.REDMINE_STATUSES['Fermé'],
gitea_redmine.REDMINE_STATUSES['Solution déployée'],
gitea_redmine.REDMINE_STATUSES['Rejeté'],
],
)
def test_handle_pull_request_opened_skips_closed_statuses(status, mocker):
redmine_user = mocker.Mock(id=42)
get_redmine_user = mocker.patch.object(gitea_redmine, 'get_redmine_user', return_value=redmine_user)
payload = {
"action": "opened",
"number": 2,
"pull_request": {
"id": 7,
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
"number": 2,
"user": {
"id": 7,
"login": "testuser",
"full_name": "Test User",
"email": "test_user@noreply.gitea.entrouvert.org",
"username": "testuser",
},
"title": "Foo",
"body": "See #70893",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock(status=mocker.Mock(id=status))
original_status = issue.status_id
gitea_redmine.handle_pull_request_opened(issue, payload, project)
assert issue.status_id == original_status
def test_handle_pull_request_edited(mocker):
redmine_user = mocker.Mock(id=42)
get_redmine_user = mocker.patch.object(gitea_redmine, 'get_redmine_user', return_value=redmine_user)
payload = {
"action": "edited",
"number": 2,
"pull_request": {
"id": 7,
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
"number": 2,
"user": {
"id": 7,
"login": "testuser",
"full_name": "Test User",
"email": "test_user@noreply.gitea.entrouvert.org",
"username": "testuser",
},
"title": "Foo",
"body": "See #70893",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock(journals=[])
gitea_redmine.handle_pull_request_edited(issue, payload, project)
get_redmine_user.assert_called_once_with('testuser')
assert issue.assigned_to_id == redmine_user.id
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['En cours']
assert issue.notes == (
'Test User (testuser) a lié une pull request sur Gitea concernant cette demande :\n\n'
'* URL : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2\n'
'* Titre : Foo\n'
'* Modifications : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2/files'
)
issue.save.assert_called_once()
def test_handle_pull_request_draft(mocker):
payload = {
"action": "edited",
"number": 2,
"pull_request": {
"id": 7,
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
"number": 2,
"user": {
"id": 7,
"login": "testuser",
"full_name": "Test User",
"email": "test_user@noreply.gitea.entrouvert.org",
"username": "testuser",
},
"title": "WIP: Foo",
"body": "See #70893",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock(journals=[])
gitea_redmine.handle_pull_request_draft(issue, payload, project)
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['En cours']
assert issue.notes == (
'Test User (testuser) a commencé à travailler sur une pull request sur Gitea concernant cette demande :\n\n'
'* URL : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2\n'
'* Titre : WIP: Foo\n'
'* Modifications : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2/files'
)
issue.save.assert_called_once()
def test_handle_pull_request_edited_already_linked_does_nothing(mocker):
payload = {
"action": "edited",
"pull_request": {
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock(
journals=[
mocker.Mock(notes='Linked to https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2')
]
)
gitea_redmine.handle_pull_request_edited(issue, payload, project)
issue.save.assert_not_called()
def test_handle_pull_request_reviewed_approved(mocker):
payload = {
"action": "reviewed",
"number": 2,
"pull_request": {
"id": 7,
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
"number": 2,
"title": "Foo",
"body": "See #70893",
"merged": True,
},
"sender": {
"id": 7,
"login": "testuser",
"full_name": "Test User",
"email": "test_user@noreply.gitea.entrouvert.org",
"username": "testuser",
},
"review": {"type": "pull_request_review_approved", "content": "Okay pour moi"},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock()
gitea_redmine.handle_pull_request_approved(issue, payload, project)
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['Solution validée']
assert issue.notes == (
'Test User (testuser) a approuvé une pull request sur Gitea concernant cette demande :\n\n'
'* URL : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2'
)
issue.save.assert_called()
def test_handle_pull_request_reviewed_rejected(mocker):
payload = {
"action": "reviewed",
"number": 2,
"pull_request": {
"id": 7,
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
"number": 2,
"title": "Foo",
"body": "See #70893",
"merged": True,
},
"sender": {
"id": 7,
"login": "testuser",
"full_name": "Test User",
"email": "test_user@noreply.gitea.entrouvert.org",
"username": "testuser",
},
"review": {"type": "pull_request_review_rejected", "content": "Des choses à changer"},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock()
gitea_redmine.handle_pull_request_rejected(issue, payload, project)
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['En cours']
assert issue.notes == (
'Test User (testuser) a relu et demandé des modifications sur une pull request sur Gitea concernant cette demande :\n\n'
'* URL : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2'
)
issue.save.assert_called_once()
def test_handle_pull_request_reviewed_approved_already_approved(mocker):
payload = {
"action": "reviewed",
"number": 2,
"pull_request": {
"id": 7,
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
"number": 2,
"title": "Foo",
"body": "See #70893",
"merged": True,
},
"sender": {
"id": 7,
"login": "testuser",
"full_name": "Test User",
"email": "test_user@noreply.gitea.entrouvert.org",
"username": "testuser",
},
"review": {"type": "pull_request_review_approved", "content": ""},
}
project = project = mocker.Mock()
project.parent = None
issue = mocker.Mock(status=mocker.Mock(id=gitea_redmine.REDMINE_STATUSES["Solution validée"]))
gitea_redmine.handle_pull_request_approved(issue, payload, project)
issue.save.assert_not_called()
def test_handle_pull_request_merged(mocker):
payload = {
"action": "closed",
"number": 2,
"pull_request": {
"id": 7,
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
"number": 2,
"title": "Foo",
"body": "See #70893",
"merged": True,
},
"sender": {
"id": 7,
"login": "testuser",
"full_name": "Test User",
"email": "test_user@noreply.gitea.entrouvert.org",
"username": "testuser",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock()
gitea_redmine.handle_pull_request_merged(issue, payload, project)
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['Résolu']
assert issue.notes == (
'Test User (testuser) a mergé une pull request sur Gitea concernant cette demande :\n\n'
'* URL : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2\n'
'* Titre : Foo\n'
'* Modifications : https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2/files'
)
issue.save.assert_called_once()
def test_incoming_webhook_requires_secret(client):
response = client.post(f'/incoming-webhook/invalid', json={})
assert response.status_code == 403
assert response.json == {'status': 'error', 'detail': 'Invalid token'}
response = client.post(
f'/incoming-webhook/{gitea_redmine.INCOMING_WEBHOOK_SECRET}',
json={'action': 'noop'},
)
assert response.status_code == 200
assert response.json == {'status': 'success', 'detail': 'Skipped, unhandled webhook'}
def test_incoming_webhook_calls_proper_handler(client, mocker):
project = mocker.Mock()
project.parent = None
issue1 = mocker.Mock(journals=[], project=project)
issue2 = mocker.Mock(journals=[], project=project)
issue3 = mocker.Mock(journals=[], project=project)
get_redmine_issue = mocker.patch.object(
gitea_redmine, 'get_redmine_issue', side_effect=[issue1, issue2, issue3]
)
get_redmine_project = mocker.patch.object(gitea_redmine, 'get_redmine_project', return_value=project)
get_handler = mocker.patch.object(gitea_redmine, 'get_handler', return_value=[mocker.Mock(), 'foo'])
payload = {
"action": "foo",
"pull_request": {
"title": "Fix #1234",
"body": "And this was caused by #5678 that should not be referenced",
"head": {"ref": "wip/9100-something"},
},
}
response = client.post(
f'/incoming-webhook/{gitea_redmine.INCOMING_WEBHOOK_SECRET}',
json=payload,
)
get_handler.assert_called_once_with(payload)
handler = get_handler.return_value[0]
assert handler.call_count == 2
get_redmine_issue.assert_any_call(1234)
get_redmine_issue.assert_any_call(9100)
handler.assert_any_call(issue1, payload, project)
handler.assert_any_call(issue2, payload, project)
assert response.status_code == 200
assert response.json == {'status': 'success', 'detail': 'Event processed and forwarded to redmine'}
def test_make_handler_ignore_excluded_projects(mocker):
f1 = mocker.Mock()
issue = mocker.Mock()
project = mocker.Mock()
is_excluded_project = mocker.patch.object(gitea_redmine, 'is_excluded_project', return_value=True)
handler = gitea_redmine.make_handler(f1)
handler(issue, {}, project)
f1.assert_not_called()
def test_excluded_project_false(mocker):
mocker.patch.object(gitea_redmine, 'REDMINE_EXCLUDED_PROJECTS', ['noop'])
project = mocker.Mock(identifier='project')
project.parent = None
assert gitea_redmine.is_excluded_project(project) is False
def test_excluded_project_true(mocker):
mocker.patch.object(gitea_redmine, 'REDMINE_EXCLUDED_PROJECTS', ['project'])
project = mocker.Mock(identifier='project')
project.parent = None
assert gitea_redmine.is_excluded_project(project) is True
def test_excluded_project_parent_true(mocker):
mocker.patch.object(gitea_redmine, 'REDMINE_EXCLUDED_PROJECTS', ['parent'])
parent = mocker.Mock(identifier='parent', id=12)
get_redmine_project = mocker.patch.object(gitea_redmine, 'get_redmine_project', return_value=parent)
project = mocker.Mock(identifier='project')
project.parent = parent
assert gitea_redmine.is_excluded_project(project) is True
def test_excluded_project_parent_false(mocker):
mocker.patch.object(gitea_redmine, 'REDMINE_EXCLUDED_PROJECTS', ['noop'])
parent = mocker.Mock(identifier='parent', id=12)
parent.parent = None
get_redmine_project = mocker.patch.object(gitea_redmine, 'get_redmine_project', return_value=parent)
project = mocker.Mock(identifier='project')
project.parent = parent
assert gitea_redmine.is_excluded_project(project) is False