491 lines
16 KiB
Python
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
|