A Python port of the Invisible Internet Project (I2P)
at main 107 lines 3.4 kB view raw
1"""Tests for HTTPProxy server — handle_client and error responses.""" 2 3import asyncio 4from unittest.mock import AsyncMock, MagicMock 5 6import pytest 7 8from i2p_apps.i2ptunnel.http_proxy import HTTPProxy 9 10 11def _mock_writer(): 12 writer = MagicMock() 13 writer.write = MagicMock() 14 writer.drain = AsyncMock() 15 writer.close = MagicMock() 16 return writer 17 18 19class TestHTTPProxyProperties: 20 def test_defaults(self): 21 proxy = HTTPProxy() 22 assert proxy.listen_address == ("127.0.0.1", 4444) 23 assert proxy.is_running is False 24 25 def test_custom(self): 26 proxy = HTTPProxy("0.0.0.0", 8080) 27 assert proxy.listen_address == ("0.0.0.0", 8080) 28 29 @pytest.mark.asyncio 30 async def test_start_stop(self): 31 proxy = HTTPProxy("127.0.0.1", 0) 32 await proxy.start() 33 assert proxy.is_running is True 34 await proxy.stop() 35 assert proxy.is_running is False 36 37 @pytest.mark.asyncio 38 async def test_stop_without_start(self): 39 proxy = HTTPProxy() 40 await proxy.stop() 41 assert proxy.is_running is False 42 43 44class TestHTTPProxyErrorResponse: 45 def test_build_error_response(self): 46 proxy = HTTPProxy() 47 resp = proxy.build_error_response(404, "Not Found") 48 text = resp.decode() 49 assert "HTTP/1.1 404 Not Found" in text 50 assert "Content-Type: text/html" in text 51 assert "<h1>404 Not Found</h1>" in text 52 53 def test_build_error_502(self): 54 proxy = HTTPProxy() 55 resp = proxy.build_error_response(502, "Bad Gateway") 56 assert b"502" in resp 57 58 59class TestHTTPProxyHandleClient: 60 @pytest.mark.asyncio 61 async def test_empty_read(self): 62 proxy = HTTPProxy() 63 reader = AsyncMock() 64 reader.readline = AsyncMock(return_value=b"") 65 writer = _mock_writer() 66 await proxy.handle_client(reader, writer) 67 writer.close.assert_called() 68 69 @pytest.mark.asyncio 70 async def test_i2p_request(self): 71 proxy = HTTPProxy() 72 reader = AsyncMock() 73 reader.readline = AsyncMock(return_value=b"GET http://example.i2p/ HTTP/1.1\r\n") 74 writer = _mock_writer() 75 await proxy.handle_client(reader, writer) 76 # Should return 502 (no I2P session) 77 written = writer.write.call_args[0][0] 78 assert b"502" in written 79 80 @pytest.mark.asyncio 81 async def test_non_i2p_request(self): 82 proxy = HTTPProxy() 83 reader = AsyncMock() 84 reader.readline = AsyncMock(return_value=b"GET http://example.com/ HTTP/1.1\r\n") 85 writer = _mock_writer() 86 await proxy.handle_client(reader, writer) 87 written = writer.write.call_args[0][0] 88 assert b"502" in written 89 90 @pytest.mark.asyncio 91 async def test_exception_closes_writer(self): 92 proxy = HTTPProxy() 93 reader = AsyncMock() 94 reader.readline = AsyncMock(side_effect=ConnectionResetError("reset")) 95 writer = _mock_writer() 96 await proxy.handle_client(reader, writer) 97 writer.close.assert_called() 98 99 @pytest.mark.asyncio 100 async def test_connect_request(self): 101 proxy = HTTPProxy() 102 reader = AsyncMock() 103 reader.readline = AsyncMock(return_value=b"CONNECT example.i2p:443 HTTP/1.1\r\n") 104 writer = _mock_writer() 105 await proxy.handle_client(reader, writer) 106 written = writer.write.call_args[0][0] 107 assert b"502" in written