"""Tests for HTTPProxy server — handle_client and error responses.""" import asyncio from unittest.mock import AsyncMock, MagicMock import pytest from i2p_apps.i2ptunnel.http_proxy import HTTPProxy def _mock_writer(): writer = MagicMock() writer.write = MagicMock() writer.drain = AsyncMock() writer.close = MagicMock() return writer class TestHTTPProxyProperties: def test_defaults(self): proxy = HTTPProxy() assert proxy.listen_address == ("127.0.0.1", 4444) assert proxy.is_running is False def test_custom(self): proxy = HTTPProxy("0.0.0.0", 8080) assert proxy.listen_address == ("0.0.0.0", 8080) @pytest.mark.asyncio async def test_start_stop(self): proxy = HTTPProxy("127.0.0.1", 0) await proxy.start() assert proxy.is_running is True await proxy.stop() assert proxy.is_running is False @pytest.mark.asyncio async def test_stop_without_start(self): proxy = HTTPProxy() await proxy.stop() assert proxy.is_running is False class TestHTTPProxyErrorResponse: def test_build_error_response(self): proxy = HTTPProxy() resp = proxy.build_error_response(404, "Not Found") text = resp.decode() assert "HTTP/1.1 404 Not Found" in text assert "Content-Type: text/html" in text assert "

404 Not Found

" in text def test_build_error_502(self): proxy = HTTPProxy() resp = proxy.build_error_response(502, "Bad Gateway") assert b"502" in resp class TestHTTPProxyHandleClient: @pytest.mark.asyncio async def test_empty_read(self): proxy = HTTPProxy() reader = AsyncMock() reader.readline = AsyncMock(return_value=b"") writer = _mock_writer() await proxy.handle_client(reader, writer) writer.close.assert_called() @pytest.mark.asyncio async def test_i2p_request(self): proxy = HTTPProxy() reader = AsyncMock() reader.readline = AsyncMock(return_value=b"GET http://example.i2p/ HTTP/1.1\r\n") writer = _mock_writer() await proxy.handle_client(reader, writer) # Should return 502 (no I2P session) written = writer.write.call_args[0][0] assert b"502" in written @pytest.mark.asyncio async def test_non_i2p_request(self): proxy = HTTPProxy() reader = AsyncMock() reader.readline = AsyncMock(return_value=b"GET http://example.com/ HTTP/1.1\r\n") writer = _mock_writer() await proxy.handle_client(reader, writer) written = writer.write.call_args[0][0] assert b"502" in written @pytest.mark.asyncio async def test_exception_closes_writer(self): proxy = HTTPProxy() reader = AsyncMock() reader.readline = AsyncMock(side_effect=ConnectionResetError("reset")) writer = _mock_writer() await proxy.handle_client(reader, writer) writer.close.assert_called() @pytest.mark.asyncio async def test_connect_request(self): proxy = HTTPProxy() reader = AsyncMock() reader.readline = AsyncMock(return_value=b"CONNECT example.i2p:443 HTTP/1.1\r\n") writer = _mock_writer() await proxy.handle_client(reader, writer) written = writer.write.call_args[0][0] assert b"502" in written