mirror of
https://github.com/boostorg/website-v2.git
synced 2026-01-19 04:42:17 +00:00
577 lines
19 KiB
Python
577 lines
19 KiB
Python
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
import responses
|
|
from ghapi.all import GhApi
|
|
from model_bakery import baker
|
|
|
|
from libraries.github import (
|
|
GithubAPIClient,
|
|
GithubDataParser,
|
|
LibraryUpdater,
|
|
)
|
|
from libraries.models import Category, Issue, Library, PullRequest
|
|
|
|
"""GithubAPIClient Tests"""
|
|
|
|
|
|
@pytest.fixture
|
|
def github_api_client():
|
|
return GithubAPIClient()
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
def mock_api() -> GhApi:
|
|
"""Fixture that mocks the GitHub API."""
|
|
with patch("libraries.github_new.GhApi") as mock_api_class:
|
|
yield mock_api_class.return_value
|
|
|
|
|
|
@pytest.fixture
|
|
def github_api_client_mock():
|
|
""" """
|
|
mock = MagicMock()
|
|
return mock
|
|
|
|
|
|
def test_initialize_api():
|
|
"""Test the initialize_api method of GitHubAPIClient."""
|
|
api = GithubAPIClient().initialize_api()
|
|
assert isinstance(api, GhApi)
|
|
|
|
|
|
def test_get_blob(github_api_client):
|
|
"""Test the get_blob method of GitHubAPIClient."""
|
|
github_api_client.api.git.get_blob = MagicMock(
|
|
return_value={"sha": "12345", "content": "example content", "encoding": "utf-8"}
|
|
)
|
|
result = github_api_client.get_blob(repo_slug="sample_repo", file_sha="12345")
|
|
assert result == {"sha": "12345", "content": "example content", "encoding": "utf-8"}
|
|
github_api_client.api.git.get_blob.assert_called_with(
|
|
owner=github_api_client.owner, repo="sample_repo", file_sha="12345"
|
|
)
|
|
|
|
###########################################################################
|
|
# Something is up with this test, it causes Pytest to fail spectacularly
|
|
# using Python 3.11. Commenting it out for now. - Frank
|
|
###########################################################################
|
|
# @pytest.mark.xfail(reason="Something up with bytes")
|
|
# @responses.activate
|
|
# def test_get_gitmodules(github_api_client):
|
|
# """Test the get_gitmodules method of GitHubAPIClient."""
|
|
# sample_ref_response = {
|
|
# "object": {
|
|
# "sha": "12345",
|
|
# }
|
|
# }
|
|
# sample_tree_response = {
|
|
# "tree": [
|
|
# {
|
|
# "path": ".gitmodules",
|
|
# "sha": "67890",
|
|
# }
|
|
# ]
|
|
# }
|
|
|
|
# sample_content = "sample content"
|
|
# sample_blob_response = {
|
|
# "content": base64.b64encode(sample_content.encode("utf-8")).decode("utf-8")
|
|
# }
|
|
|
|
# # Set up the mocked API responses
|
|
# ref_url = f"https://api.github.com/repos/{github_api_client.owner}/{github_api_client.repo_slug}/git/ref/{github_api_client.ref}"
|
|
# tree_url = f"https://api.github.com/repos/{github_api_client.owner}/{github_api_client.repo_slug}/git/trees/12345"
|
|
|
|
# responses.add(responses.GET, ref_url, json=sample_ref_response, status=200)
|
|
# responses.add(responses.GET, tree_url, json=sample_tree_response, status=200)
|
|
|
|
# # Mock the get_blob method
|
|
# github_api_client.get_blob = MagicMock(return_value=sample_blob_response)
|
|
|
|
# # Call the get_gitmodules method
|
|
# result = github_api_client.get_gitmodules(repo_slug="sample_repo")
|
|
|
|
# # Assert the expected result
|
|
# assert result == sample_content
|
|
|
|
# # Check if the API calls were made with the correct arguments
|
|
# assert len(responses.calls) == 2
|
|
# assert responses.calls[0].request.url == ref_url
|
|
# assert responses.calls[1].request.url == tree_url
|
|
# github_api_client.get_blob.assert_called_with(
|
|
# repo_slug="sample_repo", file_sha="67890"
|
|
# )
|
|
|
|
|
|
@responses.activate
|
|
def test_get_libraries_json(github_api_client):
|
|
"""Test the get_libraries_json method of GitHubAPIClient."""
|
|
repo_slug = "sample_repo"
|
|
url = f"https://raw.githubusercontent.com/{github_api_client.owner}/{repo_slug}/develop/meta/libraries.json"
|
|
sample_json = {"key": "math", "name": "Math"}
|
|
responses.add(
|
|
responses.GET,
|
|
url,
|
|
json=sample_json,
|
|
status=200,
|
|
content_type="application/json",
|
|
)
|
|
result = github_api_client.get_libraries_json(repo_slug=repo_slug)
|
|
assert result == {"key": "math", "name": "Math"}
|
|
assert len(responses.calls) == 1
|
|
assert responses.calls[0].request.url == url
|
|
|
|
|
|
def test_get_ref(github_api_client):
|
|
"""Test the get_ref method of GitHubAPIClient."""
|
|
github_api_client.api.git.get_ref = MagicMock(
|
|
return_value={"content": "example content"}
|
|
)
|
|
result = github_api_client.get_ref(repo_slug="sample_repo", ref="head/main")
|
|
assert result == {"content": "example content"}
|
|
|
|
|
|
def test_get_repo(github_api_client):
|
|
"""Test the get_repo method of GitHubAPIClient."""
|
|
github_api_client.api.repos.get = MagicMock(
|
|
return_value={"content": "example content"}
|
|
)
|
|
result = github_api_client.get_repo(repo_slug="sample_repo")
|
|
assert result == {"content": "example content"}
|
|
|
|
|
|
"""Parser Tests"""
|
|
|
|
|
|
def test_parse_gitmodules():
|
|
sample_gitmodules = """
|
|
[submodule "system"]
|
|
path = libs/system
|
|
url = ../system.git
|
|
fetchRecurseSubmodules = on-demand
|
|
branch = .
|
|
[submodule "multi_array"]
|
|
path = libs/multi_array
|
|
url = ../multi_array.git
|
|
fetchRecurseSubmodules = on-demand
|
|
branch = .
|
|
"""
|
|
|
|
parser = GithubDataParser()
|
|
parsed_data = parser.parse_gitmodules(sample_gitmodules)
|
|
|
|
expected_output = [
|
|
{
|
|
"module": "system",
|
|
"url": "system",
|
|
},
|
|
{
|
|
"module": "multi_array",
|
|
"url": "multi_array",
|
|
},
|
|
]
|
|
|
|
assert parsed_data == expected_output
|
|
|
|
|
|
def test_parse_libraries_json():
|
|
sample_libraries_json = {
|
|
"key": "math",
|
|
"name": "Math",
|
|
"authors": [],
|
|
"description": "Sample Description",
|
|
"category": ["Math"],
|
|
"maintainers": [],
|
|
"cxxstd": "14",
|
|
}
|
|
|
|
parser = GithubDataParser()
|
|
parser.parse_libraries_json(sample_libraries_json)
|
|
|
|
|
|
|
|
def test_extract_names():
|
|
sample = "Tester Testerson <tester -at- gmail.com>"
|
|
expected = ["Tester", "Testerson"]
|
|
result = GithubDataParser().extract_names(sample)
|
|
assert expected == result
|
|
|
|
sample = "Tester Testerson"
|
|
expected = ["Tester", "Testerson"]
|
|
result = GithubDataParser().extract_names(sample)
|
|
assert expected == result
|
|
|
|
sample = "Tester de Testerson <tester -at- gmail.com>"
|
|
expected = ["Tester de", "Testerson"]
|
|
result = GithubDataParser().extract_names(sample)
|
|
assert expected == result
|
|
|
|
sample = "Tester de Testerson"
|
|
expected = ["Tester de", "Testerson"]
|
|
result = GithubDataParser().extract_names(sample)
|
|
assert expected == result
|
|
|
|
sample = "Various"
|
|
expected = ["Various", ""]
|
|
result = GithubDataParser().extract_names(sample)
|
|
assert expected == result
|
|
|
|
|
|
def test_extract_email():
|
|
expected = "t_testerson@example.com"
|
|
result = GithubDataParser().extract_email(
|
|
"Tester Testerston <t_testerson -at- example.com>"
|
|
)
|
|
assert expected == result
|
|
|
|
expected = "t.t.testerson@example.com"
|
|
result = GithubDataParser().extract_email(
|
|
"Tester Testerston <t.t.testerson -at- example.com>"
|
|
)
|
|
assert expected == result
|
|
|
|
expected = "t.t.testerson@example.sample.com"
|
|
result = GithubDataParser().extract_email(
|
|
"Tester Testerston <t.t.testerson -at- example.sample.com> "
|
|
)
|
|
assert expected == result
|
|
|
|
expected = None
|
|
result = GithubDataParser().extract_email("Tester Testeron")
|
|
assert expected == result
|
|
|
|
expected = "t_tester@example.com"
|
|
result = GithubDataParser().extract_email(
|
|
"Tester Testerston <t -underscore- tester -at- example -dot- com> "
|
|
)
|
|
assert expected == result
|
|
|
|
expected = "tester@example.com"
|
|
result = GithubDataParser().extract_email(
|
|
"Tester Testerston <tester - at - example.com> "
|
|
)
|
|
assert expected == result
|
|
|
|
|
|
def test_extract_contributor_data():
|
|
sample = "Tester Testerson <tester -at- gmail.com>"
|
|
expected = {
|
|
"valid_email": True,
|
|
"email": "tester@gmail.com",
|
|
"first_name": "Tester",
|
|
"last_name": "Testerson",
|
|
}
|
|
result = GithubDataParser().extract_contributor_data(sample)
|
|
assert expected == result
|
|
|
|
sample = "Tester Testerson"
|
|
expected = {
|
|
"valid_email": False,
|
|
"first_name": "Tester",
|
|
"last_name": "Testerson",
|
|
}
|
|
result = GithubDataParser().extract_contributor_data(sample)
|
|
assert expected["valid_email"] is False
|
|
assert expected["first_name"] == result["first_name"]
|
|
assert expected["last_name"] == result["last_name"]
|
|
assert "email" in result
|
|
|
|
|
|
"""LibraryUpdater Tests"""
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_gh_api_client():
|
|
client = GithubAPIClient()
|
|
client.get_libraries_json = MagicMock(return_value=None)
|
|
client.get_repo = MagicMock(return_value=None)
|
|
client.get_gitmodules = MagicMock(return_value=b"sample content")
|
|
return client
|
|
|
|
|
|
@pytest.fixture
|
|
def library_updater(mock_gh_api_client):
|
|
return LibraryUpdater()
|
|
|
|
|
|
def test_get_library_list(library_updater):
|
|
"""Test the get_library_list method of LibraryUpdater."""
|
|
gitmodules = [{"module": "test"}]
|
|
library_updater.client.get_libraries_json = MagicMock(
|
|
return_value=[
|
|
{
|
|
"key": "test",
|
|
"name": "Test Library",
|
|
"description": "Test description",
|
|
"cxxstd": "11",
|
|
"category": ["Test"],
|
|
"authors": ["John Doe"],
|
|
"maintainers": ["Jane Doe"],
|
|
}
|
|
]
|
|
)
|
|
library_updater.client.get_repo = MagicMock(
|
|
return_value={"html_url": "example.com"}
|
|
)
|
|
expected = [
|
|
{
|
|
"key": "test",
|
|
"name": "Test Library",
|
|
"github_url": "example.com",
|
|
"description": "Test description",
|
|
"cxxstd": "11",
|
|
"last_github_update": None,
|
|
"category": ["Test"],
|
|
"authors": ["John Doe"],
|
|
"maintainers": ["Jane Doe"],
|
|
}
|
|
]
|
|
result = library_updater.get_library_list(gitmodules=gitmodules)
|
|
assert result == expected
|
|
|
|
|
|
def test_get_library_list_skip(library_updater):
|
|
"""Test that the get_library_list method of LibraryUpdater skips the right modules"""
|
|
gitmodules = [{"module": "litre"}]
|
|
result = library_updater.get_library_list(gitmodules=gitmodules)
|
|
assert result == []
|
|
|
|
|
|
def test_update_authors(library_updater, user, library_version):
|
|
library = library_version.library
|
|
assert library.authors.exists() is False
|
|
user.claimed = True
|
|
user.email = "t_testerson@example.com"
|
|
user.save()
|
|
|
|
library_updater.update_authors(
|
|
library,
|
|
authors=[
|
|
"Tester Testerston <t_testerson -at- example.com>",
|
|
"Tester2 Testerson2",
|
|
],
|
|
)
|
|
library.refresh_from_db()
|
|
assert library.authors.exists()
|
|
assert library.authors.filter(email="t_testerson@example.com").exists()
|
|
assert library.authors.filter(email="tester2_testerson2@example.com").exists()
|
|
|
|
|
|
def test_update_maintainers(library_updater, user, library_version):
|
|
assert library_version.maintainers.exists() is False
|
|
user.claimed = True
|
|
user.email = "t_testerson@example.com"
|
|
user.save()
|
|
|
|
library_updater.update_maintainers(
|
|
library_version,
|
|
maintainers=[
|
|
"Tester Testerston <t_testerson -at- example.com>",
|
|
"Tester2 Testerson2",
|
|
],
|
|
)
|
|
library_version.refresh_from_db()
|
|
assert library_version.maintainers.exists()
|
|
assert library_version.maintainers.filter(email="t_testerson@example.com").exists()
|
|
assert library_version.maintainers.filter(
|
|
email="tester2_testerson2@example.com"
|
|
).exists()
|
|
|
|
|
|
@pytest.mark.skip("Add this test when we have figured out GH API mocking")
|
|
def test_update_libraries(library_updater, version):
|
|
"""Test the update_libraries method of LibraryUpdater."""
|
|
assert Library.objects.filter(key="test").exists() is False
|
|
library_updater.parser.parse_gitmodules = MagicMock(return_value=[])
|
|
library_updater.get_library_list = MagicMock(
|
|
return_value=[
|
|
{
|
|
"key": "test",
|
|
"name": "Test Library",
|
|
"github_url": "https://github.com/test/test",
|
|
"description": "Test description",
|
|
"cxxstd": "11",
|
|
"last_github_update": None,
|
|
"category": ["Test"],
|
|
"authors": ["John Doe"],
|
|
"maintainers": ["Jane Doe"],
|
|
}
|
|
]
|
|
)
|
|
library_updater.update_libraries()
|
|
assert Library.objects.filter(key="test").exists()
|
|
|
|
|
|
def test_update_library(library_updater, version):
|
|
"""Test the update_library method of LibraryUpdater."""
|
|
assert Library.objects.filter(key="test").exists() is False
|
|
library_data = {
|
|
"key": "test",
|
|
"name": "Test Library",
|
|
"github_url": "https://github.com/test/test",
|
|
"description": "Test description",
|
|
"cxxstd": "11",
|
|
"last_github_update": None,
|
|
"category": ["Test"],
|
|
"authors": ["John Doe"],
|
|
"maintainers": ["Jane Doe"],
|
|
}
|
|
library_updater.update_library(library_data)
|
|
assert Library.objects.filter(key="test").exists()
|
|
library = Library.objects.get(key="test")
|
|
assert library.categories.filter(name="Test").exists()
|
|
|
|
|
|
def test_update_categories(library, library_updater):
|
|
"""Test the update_categories method of LibraryUpdater."""
|
|
assert Category.objects.filter(name="Test").exists() is False
|
|
assert library.categories.filter(name="Test").exists() is False
|
|
library_updater.update_categories(library, ["Test"])
|
|
library.refresh_from_db()
|
|
assert Category.objects.filter(name="Test").exists()
|
|
assert library.categories.filter(name="Test").exists()
|
|
|
|
|
|
def test_update_issues_new(
|
|
tp, library, github_api_repo_issues_response, library_updater
|
|
):
|
|
"""Test the update_issues method of LibraryUpdater with new issues."""
|
|
new_issues_count = len(github_api_repo_issues_response)
|
|
expected_count = Issue.objects.count() + new_issues_count
|
|
library_updater.client.get_repo_issues = MagicMock(
|
|
return_value=github_api_repo_issues_response
|
|
)
|
|
library_updater.update_issues(library)
|
|
|
|
ids = [issue.id for issue in github_api_repo_issues_response]
|
|
issues = Issue.objects.filter(library=library, github_id__in=ids)
|
|
assert Issue.objects.filter(library=library, github_id__in=ids).exists()
|
|
assert (
|
|
Issue.objects.filter(library=library, github_id__in=ids).count()
|
|
== expected_count
|
|
)
|
|
|
|
# Test the values of a sample Issue
|
|
gh_issue = github_api_repo_issues_response[0]
|
|
issue = issues.get(github_id=gh_issue.id)
|
|
assert issue.title == gh_issue.title
|
|
assert issue.number == gh_issue.number
|
|
if gh_issue.state == "open":
|
|
assert issue.is_open
|
|
else:
|
|
assert not issue.is_open
|
|
assert issue.data == gh_issue
|
|
|
|
|
|
def test_update_issues_existing(
|
|
tp, library, github_api_repo_issues_response, library_updater
|
|
):
|
|
"""Test the update_issues method of LibraryUpdater with existing issues."""
|
|
existing_issue_data = github_api_repo_issues_response[0]
|
|
old_title = "Old title"
|
|
issue = baker.make(
|
|
Issue, library=library, github_id=existing_issue_data.id, title=old_title
|
|
)
|
|
|
|
# Make sure we are expected one fewer new issue, since we created one in advance
|
|
new_issues_count = len(github_api_repo_issues_response)
|
|
expected_count = Issue.objects.count() + new_issues_count - 1
|
|
|
|
library_updater.client.get_repo_issues = MagicMock(
|
|
return_value=github_api_repo_issues_response
|
|
)
|
|
library_updater.update_issues(library)
|
|
|
|
assert Issue.objects.count() == expected_count
|
|
ids = [issue.id for issue in github_api_repo_issues_response]
|
|
issues = Issue.objects.filter(library=library, github_id__in=ids)
|
|
assert issues.exists()
|
|
assert issues.count() == expected_count
|
|
|
|
# Test that the existing issue updated
|
|
issue.refresh_from_db()
|
|
assert issue.title == existing_issue_data.title
|
|
|
|
|
|
def test_update_issues_long_title(
|
|
tp, library, github_api_repo_issues_response, library_updater
|
|
):
|
|
"""Test the update_issues method of LibraryUpdater handles long title gracefully"""
|
|
new_issues_count = len(github_api_repo_issues_response)
|
|
expected_count = Issue.objects.count() + new_issues_count
|
|
title = "sample" * 100
|
|
assert len(title) > 255
|
|
expected_title = title[:255]
|
|
assert len(expected_title) <= 255
|
|
|
|
github_id = github_api_repo_issues_response[0]["id"]
|
|
github_api_repo_issues_response[0]["title"] = "sample" * 100
|
|
library_updater.client.get_repo_issues = MagicMock(
|
|
return_value=github_api_repo_issues_response
|
|
)
|
|
library_updater.update_issues(library)
|
|
|
|
assert Issue.objects.count() == expected_count
|
|
assert Issue.objects.filter(library=library, github_id=github_id).exists()
|
|
issue = Issue.objects.get(library=library, github_id=github_id)
|
|
assert issue.title == expected_title
|
|
|
|
|
|
def test_update_prs_new(tp, library, github_api_repo_prs_response, library_updater):
|
|
"""Test that LibraryUpdater.update_prs() imports new PRs appropriately"""
|
|
new_prs_count = len(github_api_repo_prs_response)
|
|
expected_count = PullRequest.objects.count() + new_prs_count
|
|
|
|
github_api_repo_prs_response[0]["title"] = "sample" * 100
|
|
library_updater.client.get_repo_prs = MagicMock(
|
|
return_value=github_api_repo_prs_response
|
|
)
|
|
library_updater.update_prs(library)
|
|
|
|
assert PullRequest.objects.count() == expected_count
|
|
ids = [pr.id for pr in github_api_repo_prs_response]
|
|
pulls = PullRequest.objects.filter(library=library, github_id__in=ids)
|
|
assert pulls.exists()
|
|
assert pulls.count() == expected_count
|
|
|
|
# Test the values of a sample PR
|
|
gh_pull = github_api_repo_prs_response[0]
|
|
pr = pulls.get(github_id=gh_pull.id)
|
|
assert pr.title == gh_pull.title[:255]
|
|
assert pr.number == gh_pull.number
|
|
if gh_pull.state == "open":
|
|
assert pr.is_open
|
|
else:
|
|
assert not pr.is_open
|
|
assert pr.data == gh_pull
|
|
|
|
|
|
def test_update_prs_existing(
|
|
tp, library, github_api_repo_prs_response, library_updater
|
|
):
|
|
"""Test that LibraryUpdater.update_prs() updates existing PRs when appropriate"""
|
|
existing_pr_data = github_api_repo_prs_response[0]
|
|
old_title = "Old title"
|
|
pull = baker.make(
|
|
PullRequest, library=library, github_id=existing_pr_data.id, title=old_title
|
|
)
|
|
|
|
# Make sure we are expected one fewer new PRs, since we created one in advance
|
|
new_prs_count = len(github_api_repo_prs_response)
|
|
expected_count = PullRequest.objects.count() + new_prs_count - 1
|
|
|
|
library_updater.client.get_repo_prs = MagicMock(
|
|
return_value=github_api_repo_prs_response
|
|
)
|
|
library_updater.update_prs(library)
|
|
|
|
assert PullRequest.objects.count() == expected_count
|
|
ids = [pr.id for pr in github_api_repo_prs_response]
|
|
pulls = PullRequest.objects.filter(library=library, github_id__in=ids)
|
|
assert pulls.exists()
|
|
assert pulls.count() == expected_count
|
|
|
|
# Test that the existing PR updated
|
|
pull.refresh_from_db()
|
|
assert pull.title == existing_pr_data.title
|