mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 15:03:16 +00:00
Applies the plan's C5 step: git mv every test per the domain-reorg
move-map (movemap-m50.txt) into tests/{agent,analyzer,auth,dashboard,
github,middleware,models,reviewer,sandbox,slack,tools,webhooks}/, plus
the 13 fork-only placements from the scoping report §2c (Atlassian
webhook tests -> tests/webhooks/, test_atlassian_connect.py and
test_auth_error_leak.py -> tests/auth/, jira/confluence util tests ->
tests/tools/, test_repo_binding_isolation.py -> tests/sandbox/,
bot-identity/autofix tests -> tests/github/).
Path-only move: the only content edits are parents[1] -> parents[2]
fixes in test_e2b_integration.py and test_daytona_integration.py,
required because their __file__-relative ROOT path gained one more
directory level in the move.
Monkeypatch retargets for these files were already completed in C4;
none remained outstanding here.
161 lines
5.4 KiB
Python
161 lines
5.4 KiB
Python
"""Unit tests for GitHub CI read helpers used by the auto-fix flow."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from agent.utils import github_ci
|
|
|
|
|
|
class _FakeResponse:
|
|
def __init__(self, payload: Any = None, error: bool = False) -> None:
|
|
self._payload = payload if payload is not None else {}
|
|
self._error = error
|
|
self.status_code = 200
|
|
self.headers: dict[str, str] = {}
|
|
|
|
def raise_for_status(self) -> None:
|
|
if self._error:
|
|
raise httpx.HTTPError("boom")
|
|
|
|
def json(self) -> Any:
|
|
return self._payload
|
|
|
|
|
|
class _FakeClient:
|
|
response: _FakeResponse = _FakeResponse({})
|
|
|
|
def __init__(self, **kwargs: Any) -> None:
|
|
pass
|
|
|
|
async def __aenter__(self) -> _FakeClient:
|
|
return self
|
|
|
|
async def __aexit__(self, *_: object) -> None:
|
|
return None
|
|
|
|
async def get(self, url: str, **_: Any) -> _FakeResponse:
|
|
return type(self).response
|
|
|
|
|
|
def _patch(monkeypatch: pytest.MonkeyPatch, payload: Any, error: bool = False) -> None:
|
|
_FakeClient.response = _FakeResponse(payload, error=error)
|
|
monkeypatch.setattr(github_ci.httpx, "AsyncClient", _FakeClient)
|
|
|
|
|
|
def test_branch_and_sha_from_check_run() -> None:
|
|
payload = {
|
|
"check_run": {
|
|
"head_sha": "deadbeef",
|
|
"check_suite": {"head_branch": "feat/x"},
|
|
}
|
|
}
|
|
assert github_ci.branch_from_check_payload(payload, "check_run") == "feat/x"
|
|
assert github_ci.head_sha_from_check_payload(payload, "check_run") == "deadbeef"
|
|
|
|
|
|
def test_branch_and_sha_from_workflow_run() -> None:
|
|
payload = {"workflow_run": {"head_sha": "abc", "head_branch": "main"}}
|
|
assert github_ci.branch_from_check_payload(payload, "workflow_run") == "main"
|
|
assert github_ci.head_sha_from_check_payload(payload, "workflow_run") == "abc"
|
|
|
|
|
|
def test_sha_from_status_event() -> None:
|
|
payload = {"sha": "sha1", "branches": [{"name": "b1"}]}
|
|
assert github_ci.head_sha_from_check_payload(payload, "status") == "sha1"
|
|
assert github_ci.branch_from_check_payload(payload, "status") == "b1"
|
|
|
|
|
|
def test_is_failing_ci_payload() -> None:
|
|
assert github_ci.is_failing_ci_payload(
|
|
{"check_run": {"status": "completed", "conclusion": "failure"}}, "check_run"
|
|
)
|
|
assert not github_ci.is_failing_ci_payload(
|
|
{"check_run": {"status": "completed", "conclusion": "success"}}, "check_run"
|
|
)
|
|
assert not github_ci.is_failing_ci_payload(
|
|
{"check_run": {"status": "in_progress", "conclusion": None}}, "check_run"
|
|
)
|
|
assert github_ci.is_failing_ci_payload({"state": "failure"}, "status")
|
|
assert not github_ci.is_failing_ci_payload({"state": "pending"}, "status")
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_failing_check_runs_filters(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
_patch(
|
|
monkeypatch,
|
|
{
|
|
"check_runs": [
|
|
{"name": "lint", "status": "completed", "conclusion": "failure"},
|
|
{"name": "test", "status": "completed", "conclusion": "success"},
|
|
{"name": "build", "status": "in_progress", "conclusion": None},
|
|
{"name": "Open SWE Auto-fix", "status": "completed", "conclusion": "failure"},
|
|
]
|
|
},
|
|
)
|
|
failing = await github_ci.list_failing_check_runs(owner="o", repo="r", ref="sha", token="t")
|
|
assert failing is not None
|
|
names = {c["name"] for c in failing}
|
|
assert names == {"lint"}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_failing_check_runs_returns_none_on_error(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
_patch(monkeypatch, {}, error=True)
|
|
assert await github_ci.list_failing_check_runs(owner="o", repo="r", ref="s", token="t") is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_names_failing_on_base(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
# Both check-runs and statuses calls return the same fake payload here;
|
|
# only the check_runs shape is populated, statuses empty.
|
|
_patch(
|
|
monkeypatch,
|
|
{
|
|
"check_runs": [
|
|
{"name": "flaky", "status": "completed", "conclusion": "failure"},
|
|
],
|
|
"statuses": [],
|
|
},
|
|
)
|
|
names = await github_ci.names_failing_on_base(owner="o", repo="r", base_sha="base", token="t")
|
|
assert "flaky" in names
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_names_failing_on_base_empty_when_no_base() -> None:
|
|
assert (
|
|
await github_ci.names_failing_on_base(owner="o", repo="r", base_sha="", token="t") == set()
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_has_repo_write_permission_true(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
_patch(monkeypatch, {"permission": "write"})
|
|
assert await github_ci.has_repo_write_permission(
|
|
owner="o", repo="r", username="alice", token="t"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_has_repo_write_permission_false_for_read(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
_patch(monkeypatch, {"permission": "read"})
|
|
assert not await github_ci.has_repo_write_permission(
|
|
owner="o", repo="r", username="bob", token="t"
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_has_repo_write_permission_fails_closed(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
_patch(monkeypatch, {}, error=True)
|
|
assert not await github_ci.has_repo_write_permission(
|
|
owner="o", repo="r", username="bob", token="t"
|
|
)
|
|
assert not await github_ci.has_repo_write_permission(
|
|
owner="o", repo="r", username="", token="t"
|
|
)
|