vibe/tests/update_notifier/test_pypi_version_update_gateway.py
Mathias Gesbert 661588de0c v1.1.3
Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai>
Co-Authored-By: Michel Thomazo <michel.thomazo@mistral.ai>
Co-Authored-By: Vincent Guilloux <vincent.guilloux@mistral.ai>
2025-12-12 17:56:32 +01:00

157 lines
5.4 KiB
Python

from __future__ import annotations
from collections.abc import Callable
import httpx
import pytest
from vibe.cli.update_notifier.adapters.pypi_version_update_gateway import (
PyPIVersionUpdateGateway,
)
from vibe.cli.update_notifier.ports.version_update_gateway import (
VersionUpdate,
VersionUpdateGatewayCause,
VersionUpdateGatewayError,
)
Handler = Callable[[httpx.Request], httpx.Response]
PYPI_API_URL = "https://pypi.org"
@pytest.mark.asyncio
async def test_retrieves_nothing_when_no_versions_are_available() -> None:
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(
status_code=httpx.codes.OK, json={"versions": [], "files": []}
)
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(transport=transport, base_url=PYPI_API_URL) as client:
gateway = PyPIVersionUpdateGateway(project_name="mistral-vibe", client=client)
update = await gateway.fetch_update()
assert update is None
@pytest.mark.asyncio
async def test_retrieves_the_latest_non_yanked_version() -> None:
def handler(request: httpx.Request) -> httpx.Response:
assert request.headers["Accept"] == "application/vnd.pypi.simple.v1+json"
assert request.url.path == "/simple/mistral-vibe/"
return httpx.Response(
status_code=httpx.codes.OK,
json={
"versions": ["1.0.0", "1.0.1", "1.0.2"],
"files": [
{
"filename": "mistral_vibe-1.0.0-py3-none-any.whl",
"yanked": False,
},
{"filename": "mistral_vibe-1.0.1-py3-none-any.whl", "yanked": True},
{
"filename": "mistral_vibe-1.0.2-py3-none-any.whl",
"yanked": False,
},
],
},
)
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(transport=transport, base_url=PYPI_API_URL) as client:
gateway = PyPIVersionUpdateGateway(project_name="mistral-vibe", client=client)
update = await gateway.fetch_update()
assert update == VersionUpdate(latest_version="1.0.2")
@pytest.mark.asyncio
async def test_retrieves_nothing_when_only_yanked_versions_are_available() -> None:
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(
status_code=httpx.codes.OK,
json={
"versions": ["1.0.0"],
"files": [
{"filename": "mistral_vibe-1.0.0-py3-none-any.whl", "yanked": True}
],
},
)
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(transport=transport, base_url=PYPI_API_URL) as client:
gateway = PyPIVersionUpdateGateway(project_name="mistral-vibe", client=client)
update = await gateway.fetch_update()
assert update is None
@pytest.mark.asyncio
async def test_does_not_match_versions_by_substring() -> None:
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(
status_code=httpx.codes.OK,
json={
"versions": ["1.0.1"],
"files": [
{
"filename": "mistral_vibe-1.0.10-py3-none-any.whl",
"yanked": False,
}
],
},
)
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(transport=transport, base_url=PYPI_API_URL) as client:
gateway = PyPIVersionUpdateGateway(project_name="mistral-vibe", client=client)
update = await gateway.fetch_update()
assert update is None
def _raise_connect_timeout(request: httpx.Request) -> httpx.Response:
raise httpx.ConnectTimeout("boom", request=request)
@pytest.mark.parametrize(
("handler", "expected_cause", "expected_message"),
[
(
lambda _: httpx.Response(status_code=httpx.codes.NOT_FOUND),
VersionUpdateGatewayCause.NOT_FOUND,
None,
),
(
lambda _: httpx.Response(status_code=httpx.codes.FORBIDDEN),
VersionUpdateGatewayCause.FORBIDDEN,
None,
),
(
lambda _: httpx.Response(status_code=httpx.codes.INTERNAL_SERVER_ERROR),
VersionUpdateGatewayCause.ERROR_RESPONSE,
None,
),
(
lambda _: httpx.Response(status_code=httpx.codes.OK, content=b"{not-json"),
VersionUpdateGatewayCause.INVALID_RESPONSE,
None,
),
(_raise_connect_timeout, VersionUpdateGatewayCause.REQUEST_FAILED, None),
],
)
@pytest.mark.asyncio
async def test_retrieves_nothing_when_fetching_update_fails(
handler: Callable[[httpx.Request], httpx.Response],
expected_cause: VersionUpdateGatewayCause,
expected_message: str | None,
) -> None:
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(transport=transport, base_url=PYPI_API_URL) as client:
gateway = PyPIVersionUpdateGateway(project_name="mistral-vibe", client=client)
with pytest.raises(VersionUpdateGatewayError) as excinfo:
await gateway.fetch_update()
assert excinfo.value.cause == expected_cause
if expected_message is not None:
assert str(excinfo.value) == expected_message