Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ lint:
pipenv run pre-commit run --all-files

test:
pipenv run pytest tests/* --cov=codecov --cov-report=term-missing
pipenv run pytest tests/* --cov-branch --cov=codecov --cov-report=term-missing

report:
pipenv run pytest tests --cov-branch --cov=codecov --cov-report=term-missing --cov-report=json:/tmp/report.json
Expand Down
4 changes: 2 additions & 2 deletions codecov/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def process_pr( # pylint: disable=too-many-locals
log.info(
'Cannot post comment. This is probably because of body contents reached maximum allowed length in the comment'
)
else:
log.debug('Comment created on PR')
return 1

log.debug('Comment created on PR')
return 0
3 changes: 0 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,6 @@ ignore = ['E501', 'W503', 'W504']
[tool.pytest.ini_options]
env = ['APP_ENVIRONMENT = unittest']

[tool.coverage.run]
include = ['codecov/*']

[tool.coverage.report]
show_missing = true

Expand Down
11 changes: 11 additions & 0 deletions tests/test_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,17 @@ def test_get_diff_coverage_info(make_coverage_obj, added_lines, update_obj, expe
pathlib.Path('test.py'): [7],
},
),
(
'diff --git a/test.py b/test.py\n'
'index 1111111..2222222 100644\n'
'--- a/test.py\n'
'+++ b/test.py\n'
'@@ -5,5 +5,7 @@ def calculate_sum(a, b):\n'
' return a + b\n'
' def test_calculate_sum():\n'
' assert calculate_sum(-1, 1) == 0\n',
{},
),
],
)
def test_parse_line_number_diff_line(line_number_diff_line, expected):
Expand Down
222 changes: 168 additions & 54 deletions tests/test_main.py
Original file line number Diff line number Diff line change
@@ -1,81 +1,118 @@
# -*- coding: utf-8 -*-
import json
import pathlib
import tempfile
from unittest import mock

import pytest

from codecov import github, main


@mock.patch('codecov.main.settings.Config.from_environ')
@mock.patch('codecov.main.log.setup')
@mock.patch('codecov.main.sys.exit')
@mock.patch('codecov.main.httpx.Client')
@mock.patch('codecov.main.action')
def test_main_success(mock_action, mock_httpx_client, mock_sys_exit, mock_log_setup, mock_config_from_environ):
mock_config = mock_config_from_environ.return_value
mock_github_session = mock_httpx_client.return_value
mock_action.return_value = 0
@mock.patch('pathlib.Path.open')
def test_process_pr_skip_coverage(
mock_open: mock.Mock,
base_config,
gh,
coverage_json,
session,
caplog,
):
config = base_config(SKIP_COVERAGE=True)
caplog.set_level('INFO')
mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(coverage_json)
diff_data = 'diff --git a/file.py b/file.py\nindex 1234567..abcdefg 100644\n--- a/file.py\n+++ b/file.py\n@@ -1,2 +1,2 @@\n-foo\n+bar\n-baz\n+qux\n'
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(text=diff_data)

main.main()
repo_info = github.RepositoryInfo(default_branch='main', visibility='public')
result = main.process_pr(config, gh, repo_info, config.GITHUB_PR_NUMBER)

mock_config_from_environ.assert_called_once_with(environ=mock.ANY)
mock_log_setup.assert_called_once_with(debug=mock_config.DEBUG)
mock_action.assert_called_once_with(config=mock_config, github_session=mock_github_session)
mock_sys_exit.assert_called_once_with(0)
assert result == 0
assert caplog.records[-1].message == 'Skipping coverage report generation'


@mock.patch('codecov.main.settings.Config.from_environ')
def test_main_skip_coverage(mock_config_from_environ, base_config):
mock_config_from_environ.return_value = base_config(SKIP_COVERAGE=True)
with pytest.raises(SystemExit):
main.main()
@mock.patch('pathlib.Path.open')
def test_process_pr_skip_coverage_with_annotations(
mock_open: mock.Mock,
base_config,
gh,
coverage_json,
session,
caplog,
):
config = base_config(
SKIP_COVERAGE=True,
ANNOTATE_MISSING_LINES=True,
)
caplog.set_level('INFO')
mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(coverage_json)
diff_data = 'diff --git a/file.py b/file.py\nindex 1234567..abcdefg 100644\n--- a/file.py\n+++ b/file.py\n@@ -1,2 +1,2 @@\n-foo\n+bar\n-baz\n+qux\n'
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(text=diff_data)

repo_info = github.RepositoryInfo(default_branch='main', visibility='public')
result = main.process_pr(config, gh, repo_info, config.GITHUB_PR_NUMBER)

@mock.patch('codecov.main.settings.Config.from_environ')
@mock.patch('codecov.main.sys.exit')
@mock.patch('codecov.main.httpx.Client')
@mock.patch('codecov.main.action')
def test_main_exception(mock_action, mock_httpx_client, mock_sys_exit, mock_config_from_environ):
mock_config = mock_config_from_environ.return_value
mock_github_session = mock_httpx_client.return_value
mock_action.side_effect = Exception()
assert result == 0

main.main()

mock_config_from_environ.assert_called_once_with(environ=mock.ANY)
mock_action.assert_called_once_with(config=mock_config, github_session=mock_github_session)
mock_sys_exit.assert_called_once_with(1)
@mock.patch('pathlib.Path.open')
@mock.patch('codecov.template.read_template_file')
def test_process_pr_with_annotations_missing_marker_error(
mock_read_template_file: mock.Mock,
mock_open: mock.Mock,
base_config,
gh,
coverage_json,
session,
):
config = base_config(SUBPROJECT_ID='sub_project')
mock_read_template_file.return_value = """{% block foo %}foo{% endblock foo %}"""
mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(coverage_json)
diff_data = 'diff --git a/file.py b/file.py\nindex 1234567..abcdefg 100644\n--- a/file.py\n+++ b/file.py\n@@ -1,2 +1,2 @@\n-foo\n+bar\n-baz\n+qux\n'
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(text=diff_data)
session.register('GET', '/user')(json={'login': 'foo'})

repo_info = github.RepositoryInfo(default_branch='main', visibility='public')
result = main.process_pr(config, gh, repo_info, config.GITHUB_PR_NUMBER)

def test_action_pull_request_success(session, base_config):
config = base_config()
main.process_pr = mock.Mock(return_value=0)
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(
json={'number': config.GITHUB_PR_NUMBER, 'state': 'open'}
)
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}')(
json={'default_branch': 'baz', 'visibility': 'public'}
)
assert result == 1

result = main.action(config=config, github_session=session)

assert result == 0
@mock.patch('pathlib.Path.open')
@mock.patch('codecov.main.template.read_template_file')
def test_process_pr_with_annotations_template_error(
mock_read_template_file: mock.Mock,
mock_open: mock.Mock,
base_config,
gh,
coverage_json,
session,
):
config = base_config(
ANNOTATE_MISSING_LINES=True,
ANNOTATIONS_OUTPUT_PATH=pathlib.Path(tempfile.mkstemp(suffix='.json')[1]),
SUBPROJECT_ID='sub_project',
MINIMUM_GREEN=100,
MINIMUM_ORANGE=80,
COMPLETE_PROJECT_REPORT=True,
COVERAGE_REPORT_URL='https://example.com',
)
mock_read_template_file.return_value = '{% for i in range(5) %}{{ i }{% endfor %}'
mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(coverage_json)
diff_data = 'diff --git a/file.py b/file.py\nindex 1234567..abcdefg 100644\n--- a/file.py\n+++ b/file.py\n@@ -1,2 +1,2 @@\n-foo\n+bar\n-baz\n+qux\n'
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(text=diff_data)
session.register('GET', '/user')(json={'login': 'foo'})

repo_info = github.RepositoryInfo(default_branch='main', visibility='public')
result = main.process_pr(config, gh, repo_info, config.GITHUB_PR_NUMBER)

def test_action_pull_request_failed(session, base_config):
config = base_config()
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(status_code=404)
result = main.action(config=config, github_session=session)
assert result == 1


# TODO: Fix the test cases below
@mock.patch('pathlib.Path.open')
@mock.patch('codecov.main.template.read_template_file')
@mock.patch('codecov.main.github.post_comment')
def test_process_pr_with_annotations(
def test_process_pr_with_annotations_cannot_post(
mock_post_comment: mock.Mock,
mock_read_template_file: mock.Mock,
mock_open: mock.Mock,
Expand All @@ -86,14 +123,14 @@ def test_process_pr_with_annotations(
):
config = base_config(
ANNOTATE_MISSING_LINES=True,
ANNOTATIONS_OUTPUT_PATH=pathlib.Path('output.json'),
ANNOTATIONS_OUTPUT_PATH=pathlib.Path(tempfile.mkstemp(suffix='.json')[1]),
SUBPROJECT_ID='sub_project',
)
mock_read_template_file.return_value = """
{% block foo %}foo{% endblock foo %}
{{ marker }}
"""
mock_post_comment.return_value = None
mock_post_comment.side_effect = github.CannotPostComment
mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(coverage_json)
diff_data = 'diff --git a/file.py b/file.py\nindex 1234567..abcdefg 100644\n--- a/file.py\n+++ b/file.py\n@@ -1,2 +1,2 @@\n-foo\n+bar\n-baz\n+qux\n'
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(text=diff_data)
Expand All @@ -102,27 +139,104 @@ def test_process_pr_with_annotations(
repo_info = github.RepositoryInfo(default_branch='main', visibility='public')
result = main.process_pr(config, gh, repo_info, config.GITHUB_PR_NUMBER)

assert result == 0
assert result == 1
mock_post_comment.assert_called_once()


@mock.patch('pathlib.Path.open')
def test_process_pr_with_annotations_skip_coverage(
@mock.patch('codecov.main.template.read_template_file')
@mock.patch('codecov.main.github.post_comment')
def test_process_pr_with_annotations(
mock_post_comment: mock.Mock,
mock_read_template_file: mock.Mock,
mock_open: mock.Mock,
base_config,
gh,
coverage_json,
session,
caplog,
):
config = base_config(
ANNOTATE_MISSING_LINES=True,
ANNOTATIONS_OUTPUT_PATH=pathlib.Path('output.json'),
SKIP_COVERAGE=True,
ANNOTATIONS_OUTPUT_PATH=pathlib.Path(tempfile.mkstemp(suffix='.json')[1]),
SUBPROJECT_ID='sub_project',
)
caplog.set_level('DEBUG')
mock_read_template_file.return_value = """
{% block foo %}foo{% endblock foo %}
{{ marker }}
"""
mock_post_comment.return_value = None
mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(coverage_json)
diff_data = 'diff --git a/file.py b/file.py\nindex 1234567..abcdefg 100644\n--- a/file.py\n+++ b/file.py\n@@ -1,2 +1,2 @@\n-foo\n+bar\n-baz\n+qux\n'
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(text=diff_data)
session.register('GET', '/user')(json={'login': 'foo'})

repo_info = github.RepositoryInfo(default_branch='main', visibility='public')
result = main.process_pr(config, gh, repo_info, config.GITHUB_PR_NUMBER)

assert result == 0
assert caplog.records[-1].message == 'Comment created on PR'


@mock.patch('codecov.main.settings.Config.from_environ')
@mock.patch('codecov.main.log.setup')
@mock.patch('codecov.main.sys.exit')
@mock.patch('codecov.main.httpx.Client')
@mock.patch('codecov.main.action')
def test_main_success(mock_action, mock_httpx_client, mock_sys_exit, mock_log_setup, mock_config_from_environ):
mock_config = mock_config_from_environ.return_value
mock_github_session = mock_httpx_client.return_value
mock_action.return_value = 0

main.main()

mock_config_from_environ.assert_called_once_with(environ=mock.ANY)
mock_log_setup.assert_called_once_with(debug=mock_config.DEBUG)
mock_action.assert_called_once_with(config=mock_config, github_session=mock_github_session)
mock_sys_exit.assert_called_once_with(0)


@mock.patch('codecov.main.settings.Config.from_environ')
def test_main_skip_coverage(mock_config_from_environ, base_config):
mock_config_from_environ.return_value = base_config(SKIP_COVERAGE=True)
with pytest.raises(SystemExit):
main.main()


@mock.patch('codecov.main.settings.Config.from_environ')
@mock.patch('codecov.main.sys.exit')
@mock.patch('codecov.main.httpx.Client')
@mock.patch('codecov.main.action')
def test_main_exception(mock_action, mock_httpx_client, mock_sys_exit, mock_config_from_environ):
mock_config = mock_config_from_environ.return_value
mock_github_session = mock_httpx_client.return_value
mock_action.side_effect = Exception()

main.main()

mock_config_from_environ.assert_called_once_with(environ=mock.ANY)
mock_action.assert_called_once_with(config=mock_config, github_session=mock_github_session)
mock_sys_exit.assert_called_once_with(1)


def test_action_pull_request_success(session, base_config):
config = base_config()
main.process_pr = mock.Mock(return_value=0)
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(
json={'number': config.GITHUB_PR_NUMBER, 'state': 'open'}
)
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}')(
json={'default_branch': 'baz', 'visibility': 'public'}
)

result = main.action(config=config, github_session=session)

assert result == 0


def test_action_pull_request_failed(session, base_config):
config = base_config()
session.register('GET', f'/repos/{config.GITHUB_REPOSITORY}/pulls/{config.GITHUB_PR_NUMBER}')(status_code=404)
result = main.action(config=config, github_session=session)
assert result == 1
28 changes: 28 additions & 0 deletions tests/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,34 @@ def test_get_file_url_base():
)


def test_get_file_url_pr_base():
filename = pathlib.Path('test_file.py')
lines = (1, 10)
repo_name = 'my_repo'
pr_number = 123
base_ref = 'main'

expected_url = f'https://github.com/{repo_name}/blob/{base_ref}/{str(filename)}#L1-L10'
assert (
template.get_file_url(filename, lines, True, repo_name=repo_name, pr_number=pr_number, base_ref=base_ref)
== expected_url
)


def test_get_file_url_pr_base_no_lines():
filename = pathlib.Path('test_file.py')
lines = None
repo_name = 'my_repo'
pr_number = 123
base_ref = 'main'

expected_url = f'https://github.com/{repo_name}/blob/{base_ref}/{str(filename)}'
assert (
template.get_file_url(filename, lines, True, repo_name=repo_name, pr_number=pr_number, base_ref=base_ref)
== expected_url
)


def test_get_file_url_pr():
filename = pathlib.Path('test_file.py')
lines = (1, 10)
Expand Down