Initial commit

Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai>
Co-Authored-By: Laure Hugo <laure.hugo@mistral.ai>
Co-Authored-By: Benjamin Trom <benjamin.trom@mistral.ai>
Co-Authored-By: Mathias Gesbert <mathias.gesbert@ext.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: Valentin Berard <val@mistral.ai>
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Quentin Torroba 2025-12-09 13:13:22 +01:00 committed by Quentin Torroba
commit fa15fc977b
200 changed files with 30484 additions and 0 deletions

View file

@ -0,0 +1,249 @@
from __future__ import annotations
from collections.abc import Callable
import httpx
import pytest
from vibe.cli.update_notifier.github_version_update_gateway import (
GitHubVersionUpdateGateway,
)
from vibe.cli.update_notifier.version_update_gateway import (
VersionUpdateGatewayCause,
VersionUpdateGatewayError,
)
Handler = Callable[[httpx.Request], httpx.Response]
GITHUB_API_URL = "https://api.github.com"
def _raise_connect_timeout(request: httpx.Request) -> httpx.Response:
raise httpx.ConnectTimeout("boom", request=request)
@pytest.mark.asyncio
async def test_retrieves_latest_version_when_available() -> None:
def handler(request: httpx.Request) -> httpx.Response:
assert request.headers.get("Authorization") == "Bearer token"
return httpx.Response(
status_code=httpx.codes.OK,
json=[{"tag_name": "v1.2.3", "prerelease": False, "draft": False}],
)
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(
transport=transport, base_url=GITHUB_API_URL
) as client:
notifier = GitHubVersionUpdateGateway(
"owner", "repo", token="token", client=client
)
update = await notifier.fetch_update()
assert update is not None
assert update.latest_version == "1.2.3"
@pytest.mark.asyncio
async def test_strips_uppercase_prefix_from_tag_name() -> None:
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(
status_code=httpx.codes.OK,
json=[{"tag_name": "V0.9.0", "prerelease": False, "draft": False}],
)
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(
transport=transport, base_url=GITHUB_API_URL
) as client:
notifier = GitHubVersionUpdateGateway("owner", "repo", client=client)
update = await notifier.fetch_update()
assert update is not None
assert update.latest_version == "0.9.0"
@pytest.mark.asyncio
async def test_considers_no_update_available_when_no_releases_are_found() -> None:
"""If the repository cannot be accessed (e.g. invalid token), the response will be 404.
But using API 'releases/latest', if no release has been created, the response will ALSO be 404.
This test ensures that we consider no update available when no releases are found.
(And this is why we are using "releases" with a per_page=1 parameter, instead of "releases/latest")
"""
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(status_code=httpx.codes.OK, json=[])
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(
transport=transport, base_url=GITHUB_API_URL
) as client:
notifier = GitHubVersionUpdateGateway("owner", "repo", client=client)
update = await notifier.fetch_update()
assert update is None
@pytest.mark.asyncio
async def test_considers_no_update_available_when_only_drafts_and_prereleases_are_found() -> (
None
):
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(
status_code=httpx.codes.OK,
json=[
{"tag_name": "v2.0.0-beta", "prerelease": True, "draft": False},
{"tag_name": "v2.0.0", "prerelease": False, "draft": True},
],
)
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(
transport=transport, base_url=GITHUB_API_URL
) as client:
notifier = GitHubVersionUpdateGateway("owner", "repo", client=client)
update = await notifier.fetch_update()
assert update is None
@pytest.mark.asyncio
async def test_picks_the_most_recently_published_non_prerelease_and_non_draft() -> None:
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(
status_code=httpx.codes.OK,
json=[
{
"tag_name": "v2.0.0-beta",
"prerelease": True,
"draft": False,
"published_at": "2025-10-25T112:00:00Z",
},
{
"tag_name": "v2.0.0",
"prerelease": False,
"draft": True,
"published_at": "2025-10-26T112:00:00Z",
},
{
"tag_name": "v1.12.455",
"prerelease": False,
"draft": False,
"published_at": "2025-11-02T112:00:00Z",
},
{
"tag_name": "1.12.400",
"prerelease": False,
"draft": False,
"published_at": "2025-11-10T112:00:00Z",
},
{
"tag_name": "1.12.300",
"prerelease": False,
"draft": False,
"published_at": "2025-11-11T112:00:00Z",
},
],
)
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(
transport=transport, base_url=GITHUB_API_URL
) as client:
notifier = GitHubVersionUpdateGateway("owner", "repo", client=client)
update = await notifier.fetch_update()
assert update is not None
assert update.latest_version == "1.12.300"
@pytest.mark.parametrize(
"payload",
[
[{"tag_name": "v2.0.0-beta", "prerelease": True, "draft": False}],
[{"tag_name": "v2.0.0", "prerelease": False, "draft": True}],
],
)
@pytest.mark.asyncio
async def test_ignores_draft_releases_and_prereleases(
payload: dict[str, object],
) -> None:
def handler(request: httpx.Request) -> httpx.Response:
return httpx.Response(status_code=httpx.codes.OK, json=payload)
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(
transport=transport, base_url=GITHUB_API_URL
) as client:
notifier = GitHubVersionUpdateGateway("owner", "repo", client=client)
update = await notifier.fetch_update()
assert update is None
@pytest.mark.parametrize(
("handler", "expected_cause", "expected_custom_message"),
[
(
lambda _: httpx.Response(status_code=httpx.codes.NOT_FOUND),
VersionUpdateGatewayCause.NOT_FOUND,
"Unable to fetch the GitHub releases. Did you export a GITHUB_TOKEN environment variable?",
),
(
lambda _: httpx.Response(
status_code=httpx.codes.FORBIDDEN,
headers={"X-RateLimit-Remaining": "0"},
),
VersionUpdateGatewayCause.TOO_MANY_REQUESTS,
None,
),
(
lambda _: httpx.Response(status_code=httpx.codes.TOO_MANY_REQUESTS),
VersionUpdateGatewayCause.TOO_MANY_REQUESTS,
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, text="not json"),
VersionUpdateGatewayCause.INVALID_RESPONSE,
None,
),
(_raise_connect_timeout, VersionUpdateGatewayCause.REQUEST_FAILED, None),
],
ids=[
"not_found",
"rate_limit_header",
"rate_limit_status",
"forbidden",
"error_response",
"invalid_json",
"request_error",
],
)
@pytest.mark.asyncio
async def test_retrieves_nothing_when_fetching_update_fails(
handler: Handler,
expected_cause: VersionUpdateGatewayCause,
expected_custom_message: str | None,
) -> None:
transport = httpx.MockTransport(handler)
async with httpx.AsyncClient(
transport=transport, base_url=GITHUB_API_URL
) as client:
notifier = GitHubVersionUpdateGateway("owner", "repo", client=client)
with pytest.raises(VersionUpdateGatewayError) as excinfo:
await notifier.fetch_update()
assert excinfo.value.cause == expected_cause
if expected_custom_message is not None:
assert str(excinfo.value) == expected_custom_message