Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai> Co-Authored-By: Michel Thomazo <michel.thomazo@mistral.ai> Co-Authored-By: Clément Drouin <clement.drouin@mistral.ai> Co-Authored-By: Vincent Guilloux <vincent.guilloux@mistral.ai> Co-Authored-By: Clément Siriex <clement.sirieix@mistral.ai> Co-Authored-By: Kim-Adeline Miguel <kimadeline.miguel@mistral.ai> Co-Authored-By: Thaddee Tyl <thaddee.tyl@gmail.com> Co-Authored-By: David Brochart <david.brochart@gmail.com> Co-Authored-By: Joseph Guhlin <joseph.guhlin@gmail.com> Co-Authored-By: Thomas Kenbeek <thomaskenbeek@gmail.com> Co-Authored-By: Remenby31 <baptiste.cruvellier31@gmail.com>
155 lines
5.2 KiB
Python
155 lines
5.2 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
|
|
import httpx
|
|
import pytest
|
|
|
|
from vibe.cli.update_notifier.adapters.pypi_update_gateway import PyPIUpdateGateway
|
|
from vibe.cli.update_notifier.ports.update_gateway import (
|
|
Update,
|
|
UpdateGatewayCause,
|
|
UpdateGatewayError,
|
|
)
|
|
|
|
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 = PyPIUpdateGateway(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 = PyPIUpdateGateway(project_name="mistral-vibe", client=client)
|
|
update = await gateway.fetch_update()
|
|
|
|
assert update == Update(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 = PyPIUpdateGateway(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 = PyPIUpdateGateway(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),
|
|
UpdateGatewayCause.NOT_FOUND,
|
|
None,
|
|
),
|
|
(
|
|
lambda _: httpx.Response(status_code=httpx.codes.FORBIDDEN),
|
|
UpdateGatewayCause.FORBIDDEN,
|
|
None,
|
|
),
|
|
(
|
|
lambda _: httpx.Response(status_code=httpx.codes.INTERNAL_SERVER_ERROR),
|
|
UpdateGatewayCause.ERROR_RESPONSE,
|
|
None,
|
|
),
|
|
(
|
|
lambda _: httpx.Response(status_code=httpx.codes.OK, content=b"{not-json"),
|
|
UpdateGatewayCause.INVALID_RESPONSE,
|
|
None,
|
|
),
|
|
(_raise_connect_timeout, UpdateGatewayCause.REQUEST_FAILED, None),
|
|
],
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_retrieves_nothing_when_fetching_update_fails(
|
|
handler: Callable[[httpx.Request], httpx.Response],
|
|
expected_cause: UpdateGatewayCause,
|
|
expected_message: str | None,
|
|
) -> None:
|
|
transport = httpx.MockTransport(handler)
|
|
async with httpx.AsyncClient(transport=transport, base_url=PYPI_API_URL) as client:
|
|
gateway = PyPIUpdateGateway(project_name="mistral-vibe", client=client)
|
|
with pytest.raises(UpdateGatewayError) as excinfo:
|
|
await gateway.fetch_update()
|
|
|
|
assert excinfo.value.cause == expected_cause
|
|
if expected_message is not None:
|
|
assert str(excinfo.value) == expected_message
|