mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 06:53:14 +00:00
148 lines
5.1 KiB
Python
148 lines
5.1 KiB
Python
"""Unit tests for create_github_pr HTTP error fallback behavior."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from agent.utils.github import create_github_pr
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_github_pr_existing_pr_preserves_description():
|
|
"""Existing PRs should be reused without overwriting their title or body."""
|
|
existing_pr_url = "https://github.com/owner/repo/pull/42"
|
|
existing_pr_number = 42
|
|
create_response = MagicMock()
|
|
create_response.status_code = 422
|
|
create_response.json.return_value = {"message": "Validation Failed"}
|
|
|
|
mock_client = MagicMock()
|
|
mock_client.post = AsyncMock(return_value=create_response)
|
|
mock_client.patch = AsyncMock()
|
|
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
mock_client.__aexit__ = AsyncMock(return_value=False)
|
|
|
|
with (
|
|
patch("httpx.AsyncClient", return_value=mock_client),
|
|
patch(
|
|
"agent.utils.github._find_existing_pr",
|
|
AsyncMock(return_value=(existing_pr_url, existing_pr_number)),
|
|
),
|
|
patch("agent.utils.github._add_label", AsyncMock()),
|
|
):
|
|
pr_url, pr_number, pr_existing = await create_github_pr(
|
|
repo_owner="owner",
|
|
repo_name="repo",
|
|
github_token="token",
|
|
title="Test PR",
|
|
head_branch="feature/test",
|
|
base_branch="main",
|
|
body="new generated body",
|
|
)
|
|
|
|
assert pr_url == existing_pr_url
|
|
assert pr_number == existing_pr_number
|
|
assert pr_existing is True
|
|
mock_client.patch.assert_not_awaited()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_github_pr_http_error_falls_back_to_existing_pr():
|
|
"""When httpx.HTTPError is raised during PR creation, the function should
|
|
fall back to _find_existing_pr and return the existing PR if one is found.
|
|
|
|
Guards against regression where transient network errors after a successful
|
|
GitHub PR creation would cause a false 'Failed to create GitHub PR' result.
|
|
"""
|
|
existing_pr_url = "https://github.com/owner/repo/pull/42"
|
|
existing_pr_number = 42
|
|
|
|
mock_post = AsyncMock(side_effect=httpx.HTTPError("connection reset"))
|
|
mock_find = AsyncMock(return_value=(existing_pr_url, existing_pr_number))
|
|
|
|
mock_client = MagicMock()
|
|
mock_client.post = mock_post
|
|
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
mock_client.__aexit__ = AsyncMock(return_value=False)
|
|
|
|
with (
|
|
patch("httpx.AsyncClient", return_value=mock_client),
|
|
patch("agent.utils.github._find_existing_pr", mock_find),
|
|
):
|
|
pr_url, pr_number, pr_existing = await create_github_pr(
|
|
repo_owner="owner",
|
|
repo_name="repo",
|
|
github_token="token",
|
|
title="Test PR",
|
|
head_branch="feature/test",
|
|
base_branch="main",
|
|
body="PR body",
|
|
)
|
|
|
|
assert pr_url == existing_pr_url
|
|
assert pr_number == existing_pr_number
|
|
assert pr_existing is True
|
|
mock_find.assert_awaited_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_github_pr_http_error_returns_none_when_no_existing_pr():
|
|
"""When httpx.HTTPError is raised and no existing PR is found, return (None, None, False)."""
|
|
mock_post = AsyncMock(side_effect=httpx.HTTPError("connection reset"))
|
|
mock_find = AsyncMock(return_value=(None, None))
|
|
|
|
mock_client = MagicMock()
|
|
mock_client.post = mock_post
|
|
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
mock_client.__aexit__ = AsyncMock(return_value=False)
|
|
|
|
with (
|
|
patch("httpx.AsyncClient", return_value=mock_client),
|
|
patch("agent.utils.github._find_existing_pr", mock_find),
|
|
):
|
|
pr_url, pr_number, pr_existing = await create_github_pr(
|
|
repo_owner="owner",
|
|
repo_name="repo",
|
|
github_token="token",
|
|
title="Test PR",
|
|
head_branch="feature/test",
|
|
base_branch="main",
|
|
body="PR body",
|
|
)
|
|
|
|
assert pr_url is None
|
|
assert pr_number is None
|
|
assert pr_existing is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_github_pr_http_error_returns_none_when_find_also_fails():
|
|
"""When httpx.HTTPError is raised and _find_existing_pr also raises, return (None, None, False)."""
|
|
mock_post = AsyncMock(side_effect=httpx.HTTPError("connection reset"))
|
|
mock_find = AsyncMock(side_effect=Exception("secondary failure"))
|
|
|
|
mock_client = MagicMock()
|
|
mock_client.post = mock_post
|
|
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
mock_client.__aexit__ = AsyncMock(return_value=False)
|
|
|
|
with (
|
|
patch("httpx.AsyncClient", return_value=mock_client),
|
|
patch("agent.utils.github._find_existing_pr", mock_find),
|
|
):
|
|
pr_url, pr_number, pr_existing = await create_github_pr(
|
|
repo_owner="owner",
|
|
repo_name="repo",
|
|
github_token="token",
|
|
title="Test PR",
|
|
head_branch="feature/test",
|
|
base_branch="main",
|
|
body="PR body",
|
|
)
|
|
|
|
assert pr_url is None
|
|
assert pr_number is None
|
|
assert pr_existing is False
|