from __future__ import annotations import httpx import pytest import respx from tests.conftest import build_test_vibe_config from vibe.cli.plan_offer.adapters.http_whoami_gateway import HttpWhoAmIGateway from vibe.cli.plan_offer.ports.whoami_gateway import ( WhoAmIGatewayError, WhoAmIGatewayUnauthorized, WhoAmIPlanType, WhoAmIResponse, ) from vibe.core.config import DEFAULT_CONSOLE_BASE_URL @pytest.mark.asyncio async def test_returns_plan_flags(respx_mock: respx.MockRouter) -> None: route = respx_mock.get("http://test/api/vibe/whoami").mock( return_value=httpx.Response( 200, json={ "plan_type": "CHAT", "plan_name": "INDIVIDUAL", "prompt_switching_to_pro_plan": False, }, ) ) gateway = HttpWhoAmIGateway(base_url="http://test") response = await gateway.whoami("api-key") assert route.called request = route.calls.last.request assert request.headers["Authorization"] == "Bearer api-key" assert response.plan_type == "CHAT" assert response.plan_name == "INDIVIDUAL" assert response.prompt_switching_to_pro_plan is False @pytest.mark.asyncio @pytest.mark.parametrize("status_code", [401, 403]) async def test_raises_on_unauthorized( respx_mock: respx.MockRouter, status_code: int ) -> None: respx_mock.get("http://test/api/vibe/whoami").mock( return_value=httpx.Response(status_code, json={"error": "unauthorized"}) ) gateway = HttpWhoAmIGateway(base_url="http://test") with pytest.raises(WhoAmIGatewayUnauthorized): await gateway.whoami("bad-key") @pytest.mark.asyncio async def test_raises_on_non_success(respx_mock: respx.MockRouter) -> None: respx_mock.get("http://test/api/vibe/whoami").mock( return_value=httpx.Response(500, json={"error": "boom"}) ) gateway = HttpWhoAmIGateway(base_url="http://test") with pytest.raises(WhoAmIGatewayError): await gateway.whoami("api-key") @pytest.mark.asyncio async def test_incomplete_payload_defaults_missing_flags_to_false( respx_mock: respx.MockRouter, ) -> None: respx_mock.get("http://test/api/vibe/whoami").mock( return_value=httpx.Response( 200, json={"plan_type": "CHAT", "plan_name": "INDIVIDUAL"} ) ) gateway = HttpWhoAmIGateway(base_url="http://test") response = await gateway.whoami("api-key") assert response == WhoAmIResponse( plan_type=WhoAmIPlanType.CHAT, plan_name="INDIVIDUAL", prompt_switching_to_pro_plan=False, ) @pytest.mark.asyncio async def test_raises_on_missing_plan_info(respx_mock: respx.MockRouter) -> None: respx_mock.get("http://test/api/vibe/whoami").mock( return_value=httpx.Response(200, json={"prompt_switching_to_pro_plan": False}) ) gateway = HttpWhoAmIGateway(base_url="http://test") with pytest.raises(WhoAmIGatewayError): await gateway.whoami("api-key") @pytest.mark.asyncio async def test_wraps_request_error(respx_mock: respx.MockRouter) -> None: respx_mock.get("http://test/api/vibe/whoami").mock( side_effect=httpx.ConnectError("boom") ) gateway = HttpWhoAmIGateway(base_url="http://test") with pytest.raises(WhoAmIGatewayError): await gateway.whoami("api-key") @pytest.mark.asyncio async def test_parses_boolean_strings(respx_mock: respx.MockRouter) -> None: respx_mock.get("http://test/api/vibe/whoami").mock( return_value=httpx.Response( 200, json={ "plan_type": "API", "plan_name": "FREE", "prompt_switching_to_pro_plan": "false", }, ) ) gateway = HttpWhoAmIGateway(base_url="http://test") response = await gateway.whoami("api-key") assert response == WhoAmIResponse( plan_type=WhoAmIPlanType.API, plan_name="FREE", prompt_switching_to_pro_plan=False, ) @pytest.mark.asyncio async def test_raises_on_invalid_boolean_string(respx_mock: respx.MockRouter) -> None: respx_mock.get("http://test/api/vibe/whoami").mock( return_value=httpx.Response( 200, json={ "plan_type": "CHAT", "plan_name": "INDIVIDUAL", "prompt_switching_to_pro_plan": "something", }, ) ) gateway = HttpWhoAmIGateway(base_url="http://test") with pytest.raises(WhoAmIGatewayError): await gateway.whoami("api-key") @pytest.mark.asyncio async def test_return_unknown_plan_on_unsupported_plan_type( respx_mock: respx.MockRouter, ) -> None: respx_mock.get("http://test/api/vibe/whoami").mock( return_value=httpx.Response( 200, json={ "plan_type": "SOMETHING", "plan_name": "INDIVIDUAL", "prompt_switching_to_pro_plan": "false", }, ) ) gateway = HttpWhoAmIGateway(base_url="http://test") response = await gateway.whoami("api-key") assert response == WhoAmIResponse( plan_type=WhoAmIPlanType.UNKNOWN, plan_name="INDIVIDUAL", prompt_switching_to_pro_plan=False, ) @pytest.mark.asyncio async def test_gateway_calls_custom_console_base_url_from_config( respx_mock: respx.MockRouter, ) -> None: custom_url = "https://custom-console.example.com" config = build_test_vibe_config(console_base_url=custom_url) route = respx_mock.get(f"{custom_url}/api/vibe/whoami").mock( return_value=httpx.Response( 200, json={ "plan_type": "CHAT", "plan_name": "INDIVIDUAL", "prompt_switching_to_pro_plan": False, }, ) ) gateway = HttpWhoAmIGateway(base_url=config.console_base_url) response = await gateway.whoami("api-key") assert route.called assert response.plan_type == "CHAT" @pytest.mark.asyncio async def test_gateway_uses_default_console_url_when_not_configured( respx_mock: respx.MockRouter, ) -> None: config = build_test_vibe_config() assert config.console_base_url == DEFAULT_CONSOLE_BASE_URL route = respx_mock.get(f"{DEFAULT_CONSOLE_BASE_URL}/api/vibe/whoami").mock( return_value=httpx.Response( 200, json={ "plan_type": "CHAT", "plan_name": "INDIVIDUAL", "prompt_switching_to_pro_plan": False, }, ) ) gateway = HttpWhoAmIGateway(base_url=config.console_base_url) await gateway.whoami("api-key") assert route.called