mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 16:13:15 +00:00
- Root cause: httpx.HTTPError handler returned (None, None, False) without checking if the PR was already created on GitHub before the network error - Change: added _find_existing_pr fallback in except block in agent/utils/github.py - Verified: 5 production traces showed false failures where PR existed (pr_existing=True on retry) Co-authored-by: LangSmith Forge <forge-agent@langsmith.ai> Co-authored-by: Johannes du Plessis <johannes@langchain.dev>
109 lines
3.7 KiB
Python
109 lines
3.7 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_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
|