Skip to content

Commit

Permalink
feat(test): add tests and GH workflow for pytest
Browse files Browse the repository at this point in the history
  • Loading branch information
tomassebestik committed Feb 9, 2024
1 parent 03e2ab1 commit 868bba9
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 0 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/python-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Python Tests

on:
pull_request:

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.9
uses: actions/setup-python@v5
with:
python-version: 3.9

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-cov
pip install -r requirements.txt
- name: Run pytest with coverage
run: |
python -m pytest
11 changes: 11 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,14 @@
]
[tool.pylint.'FORMAT']
max-line-length = 120 # Specifies the maximum line length for pylint checks


[tool.pytest.ini_options]
addopts = "-s --log-cli-level DEBUG --cov=. --cov-report=term"
python_classes = ["Test*"]
python_files = ["test_*.py"]
python_functions = ["test_*"]
testpaths = ["tests"]

[tool.coverage.run]
omit = ["__*__.py", "tests/*"]
97 changes: 97 additions & 0 deletions tests/test_sync_issue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from unittest.mock import MagicMock
from unittest.mock import patch

import pytest


@pytest.fixture(autouse=True)
def setup_env(monkeypatch):
monkeypatch.setenv('GITHUB_TOKEN', 'fake-token')
monkeypatch.setenv('GITHUB_REPOSITORY', 'fake/repo')


@pytest.fixture(scope='module')
def github_client_mock():
with patch('github.Github') as MockGithub:
mock_github = MockGithub.return_value
mock_repo = MagicMock()
mock_github.get_repo.return_value = mock_repo
yield mock_github, mock_repo


# Correct fixture to mock JIRA client
@pytest.fixture(scope='module')
def mock_jira_client():
with patch('jira.JIRA') as MockJIRA:
mock_jira = MockJIRA.return_value
yield mock_jira


@pytest.fixture
def sync_issue_module(github_client_mock):
from importlib import reload
import sync_issue

reload(sync_issue) # Reload to apply the mocked Github client
return sync_issue


# Example test function
def test_handle_issue_opened_creates_jira_issue(sync_issue_module, github_client_mock):
_, mock_repo = github_client_mock
mock_jira_client = MagicMock()
mock_event = {
'issue': {
'number': 123,
'title': 'New Issue',
'body': 'Issue description here.',
'user': {'login': 'user123'},
'labels': [],
'html_url': 'https://github.com/user/repo/issues/123',
'state': 'open',
}
}

with patch('sync_issue._find_jira_issue', return_value=None) as mock_find_jira_issue, patch(
'sync_issue._create_jira_issue'
) as mock_create_jira_issue:
sync_issue_module.handle_issue_opened(mock_jira_client, mock_event)

mock_find_jira_issue.assert_called_once()
mock_create_jira_issue.assert_called_once()


def test_handle_issue_labeled_adds_label(sync_issue_module, github_client_mock, mock_jira_client):
# Setup
mock_github, mock_repo = github_client_mock

mock_event = {
'issue': {
'number': 123,
'title': 'Issue for Labeling',
'body': 'Label me!',
'user': {'login': 'user456'},
'labels': [{'name': 'bug'}],
'html_url': 'https://github.com/user/repo/issues/123',
'state': 'open',
},
'label': {'name': 'bug'},
}

# Adjusting the mock to behave more like a list that can be appended to
mock_jira_issue = MagicMock()
labels_list = ['existing-label'] # Starting with an existing label for demonstration
mock_jira_issue.fields.labels = labels_list

def update_labels(fields=None):
if fields and 'labels' in fields:
labels_list.extend(fields['labels']) # Simulate adding new labels

mock_jira_issue.update = MagicMock(side_effect=update_labels)

with patch('sync_issue._find_jira_issue', return_value=mock_jira_issue), patch(
'sync_issue._get_jira_label', side_effect=lambda x: x['name']
):
sync_issue_module.handle_issue_labeled(mock_jira_client, mock_event)

assert 'bug' in labels_list, "Label 'bug' was not added to the JIRA issue labels"
68 changes: 68 additions & 0 deletions tests/test_sync_pr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import importlib
from unittest.mock import MagicMock
from unittest.mock import patch

import pytest


# Patch the GitHub client before importing modules that use it
@pytest.fixture(autouse=True)
def mock_env_vars(monkeypatch):
monkeypatch.setenv('GITHUB_TOKEN', 'fake-token')
monkeypatch.setenv('GITHUB_REPOSITORY', 'fake/repo')


@pytest.fixture
def mock_github():
with patch('github.Github') as MockGithub:
mock_repo = MagicMock()
mock_pr = MagicMock()
mock_pr.number = 1
mock_pr.title = 'Test PR'
mock_pr.html_url = 'http://example.com/testpr'
mock_pr.user.login = 'testuser'
mock_pr.labels = []
mock_pr.state = 'open'
mock_pr.body = 'Test body'
mock_repo.get_pulls.return_value = [mock_pr]
mock_repo.has_in_collaborators.return_value = False

MockGithub.return_value.get_repo.return_value = mock_repo
yield mock_repo


@pytest.fixture
def sync_pr_module(mock_github):
# Import the module
import sync_pr

# Reload the module to ensure the mock is applied
importlib.reload(sync_pr)
# Return the reloaded module
return sync_pr


@pytest.fixture
def mock_sync_issue():
with patch('sync_pr._create_jira_issue') as mock_create_jira_issue, patch(
'sync_pr._find_jira_issue', return_value=None
) as mock_find_jira_issue:
yield mock_create_jira_issue, mock_find_jira_issue


def test_sync_remain_prs(sync_pr_module, mock_sync_issue, mock_github):
mock_jira = MagicMock()
mock_create_jira_issue, mock_find_jira_issue = mock_sync_issue

# Use the function from the reloaded module
sync_pr_module.sync_remain_prs(mock_jira)

# Verify _find_jira_issue was called once with the mock_jira client and the PR data
assert mock_find_jira_issue.call_count == 1

# Verify _create_jira_issue was called once since no corresponding JIRA issue was found
assert mock_create_jira_issue.call_count == 1

# Example of verifying call arguments (simplified)
call_args = mock_create_jira_issue.call_args
assert 'Test PR' in call_args[0][1]['title'], 'PR title does not match expected value'
61 changes: 61 additions & 0 deletions tests/test_sync_to_jira.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import json
from unittest.mock import MagicMock
from unittest.mock import patch

import pytest


@pytest.fixture
def mock_environment(tmp_path, monkeypatch):
event_file = tmp_path / 'event.json'
monkeypatch.setenv('GITHUB_REPOSITORY', 'espressif/esp-idf')
monkeypatch.setenv('GITHUB_TOKEN', 'fake-token')
monkeypatch.setenv('GITHUB_EVENT_PATH', str(event_file))
monkeypatch.setenv('JIRA_URL', 'https://jira.example.com')
monkeypatch.setenv('JIRA_USER', 'user')
monkeypatch.setenv('JIRA_PASS', 'pass')
return event_file


@pytest.fixture
def sync_to_jira_main(monkeypatch):
monkeypatch.setattr('github.Github', MagicMock())
monkeypatch.setattr('jira.JIRA', MagicMock())

# Import the main function dynamically after applying mocks
from sync_to_jira import main as dynamically_imported_main

return dynamically_imported_main


def test_not_running_in_github_action_context(capsys, sync_to_jira_main, monkeypatch):
monkeypatch.delenv('GITHUB_REPOSITORY', raising=False)
sync_to_jira_main()
captured = capsys.readouterr()
assert 'Not running in GitHub action context, nothing to do' in captured.out


def test_not_espressif_repo(capsys, sync_to_jira_main, monkeypatch):
monkeypatch.setenv('GITHUB_REPOSITORY', 'other/repo')
sync_to_jira_main()
captured = capsys.readouterr()
assert 'Not an Espressif repo, nothing to sync to JIRA' in captured.out


def test_handle_issue_opened_event(mock_environment, sync_to_jira_main, monkeypatch):
event_data = {
'action': 'opened',
'issue': {
'number': 1,
'title': 'Test issue',
'body': 'This is a test issue',
'user': {'login': 'testuser'},
'html_url': 'https://github.com/espressif/esp-idf/issues/1',
},
}
mock_environment.write_text(json.dumps(event_data))
monkeypatch.setenv('GITHUB_EVENT_NAME', 'issues')

with patch('sync_to_jira.handle_issue_opened') as mock_handle_issue_opened:
sync_to_jira_main()
mock_handle_issue_opened.assert_called_once()

0 comments on commit 868bba9

Please sign in to comment.