from __future__ import annotations from unittest.mock import Mock from lai_automation.gitea import GiteaClient from lai_automation.models import Issue, Label def response(payload, status: int = 200) -> Mock: result = Mock() result.json.return_value = payload result.status_code = status result.text = "" result.raise_for_status.return_value = None return result def test_list_queued_issues_filters_pull_requests(settings) -> None: client = GiteaClient(settings) client.session.request = Mock( return_value=response( [ { "number": 7, "title": "Wrong answer", "body": "Details", "html_url": "https://gitea.example.test/owner/lai/issues/7", "labels": [{"id": 1, "name": "ai:queued"}], }, { "number": 8, "title": "A pull request", "body": "", "html_url": "https://gitea.example.test/owner/lai/pulls/8", "labels": [{"id": 1, "name": "ai:queued"}], "pull_request": {"merged": False}, }, ] ) ) issues = client.list_queued_issues() assert [issue.number for issue in issues] == [7] assert client.session.request.call_args.kwargs["params"]["labels"] == "ai:queued" def test_ensure_automation_labels_creates_only_missing_labels(settings) -> None: client = GiteaClient(settings) existing = [{"id": 1, "name": "ai:queued"}] created = iter( [ {"id": 2, "name": "ai:running"}, {"id": 3, "name": "ai:ready"}, {"id": 4, "name": "ai:failed"}, ] ) def request(method, _url, **kwargs): if method == "GET": return response(existing) return response(next(created)) client.session.request = Mock(side_effect=request) labels = client.ensure_automation_labels() assert set(labels) == {"ai:queued", "ai:running", "ai:ready", "ai:failed"} assert client.session.request.call_count == 4 def test_state_transition_preserves_manual_labels(settings) -> None: client = GiteaClient(settings) client.session.request = Mock( side_effect=[ response( [ {"id": 9, "name": "bug"}, {"id": 2, "name": "ai:running"}, ] ), response( { "number": 5, "title": "Issue", "body": "Body", "html_url": "https://gitea.example.test/owner/lai/issues/5", "labels": [ {"id": 9, "name": "bug"}, {"id": 2, "name": "ai:running"}, ], } ), ] ) issue = Issue( number=5, title="Issue", body="Body", html_url="https://gitea.example.test/owner/lai/issues/5", labels=(Label(9, "bug"), Label(1, "ai:queued")), ) known = { "ai:queued": Label(1, "ai:queued"), "ai:running": Label(2, "ai:running"), } updated = client.set_automation_state(issue, "ai:running", known) assert updated.has_label("ai:running") replace_call = client.session.request.call_args_list[0] assert replace_call.args[0] == "PUT" assert replace_call.args[1].endswith("/issues/5/labels") assert replace_call.kwargs["json"] == {"labels": [9, 2]} assert client.session.request.call_args_list[1].args[0] == "GET" def test_create_pull_request_returns_number_and_url(settings) -> None: client = GiteaClient(settings) client.session.request = Mock( return_value=response( {"number": 17, "html_url": "https://gitea.example.test/owner/lai/pulls/17"} ) ) pull_request = client.create_pull_request("ai/issue-5", "Fix", "Fixes #5") assert pull_request.number == 17 assert pull_request.html_url.endswith("/pulls/17") assert client.session.request.call_args.kwargs["json"]["base"] == "main"