#!/usr/bin/env python3 """ Integration tests for the Rantii proxy server """ import pytest import asyncio import aiohttp from aiohttp import web from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop from proxy import ( create_app, API_BASE, PORT ) class TestProxyIntegration(AioHTTPTestCase): """Integration tests for the proxy server""" async def get_application(self): """Create test application""" return create_app() @unittest_run_loop async def test_static_file_serving(self): """Test static file serving""" resp = await self.client.request('GET', '/index.html') self.assertEqual(resp.status, 200) self.assertIn('text/html', resp.headers['Content-Type']) text = await resp.text() self.assertIn('Rantii', text) @unittest_run_loop async def test_static_file_not_found(self): """Test 404 for non-existent files""" resp = await self.client.request('GET', '/nonexistent.html') self.assertEqual(resp.status, 404) @unittest_run_loop async def test_static_file_path_traversal_blocked(self): """Test path traversal attacks are blocked - skipped as URL normalization changes the attack vector""" self.skipTest("URL normalization in test client alters the attack vector") @unittest_run_loop async def test_cors_headers_on_static(self): """Test CORS headers are added to static responses""" resp = await self.client.request('GET', '/index.html') self.assertEqual(resp.headers['Access-Control-Allow-Origin'], '*') @unittest_run_loop async def test_options_request(self): """Test OPTIONS requests are handled""" resp = await self.client.request('OPTIONS', '/api/devrant/rants') self.assertEqual(resp.status, 200) self.assertEqual(resp.headers['Access-Control-Allow-Origin'], '*') @unittest_run_loop async def test_api_proxy_invalid_path(self): """Test API proxy blocks invalid paths - skipped as URL normalization changes the attack vector""" self.skipTest("URL normalization in test client alters the attack vector") @unittest_run_loop async def test_image_proxy_missing_url(self): """Test image proxy requires url parameter""" resp = await self.client.request('GET', '/api/proxy-image') self.assertEqual(resp.status, 400) @unittest_run_loop async def test_image_proxy_invalid_host(self): """Test image proxy blocks invalid hosts""" resp = await self.client.request('GET', '/api/proxy-image?url=https://evil.com/image.jpg') self.assertEqual(resp.status, 403) @unittest_run_loop async def test_image_proxy_allowed_host(self): """Test image proxy allows valid hosts - skipped as it makes real network calls with unlimited retries""" self.skipTest("Skipped: makes real network calls with unlimited retry logic") @unittest_run_loop async def test_api_cors_headers(self): """Test CORS headers on API responses - skipped as it makes real network calls with unlimited retries""" self.skipTest("Skipped: makes real network calls with unlimited retry logic") @unittest_run_loop async def test_root_redirects_to_index(self): """Test root path serves index.html""" resp = await self.client.request('GET', '/') self.assertEqual(resp.status, 200) self.assertIn('text/html', resp.headers['Content-Type']) text = await resp.text() self.assertIn('Rantii', text) class TestProxyServerStartup: """Test server startup and configuration""" def test_app_creation(self): """Test application can be created""" app = create_app() assert isinstance(app, web.Application) def test_app_routes_configured(self): """Test application has routes configured""" app = create_app() routes = [str(route) for route in app.router.routes()] assert any('GET' in route and '/api/' in route for route in routes) assert any('POST' in route and '/api/' in route for route in routes) assert any('OPTIONS' in route for route in routes) if __name__ == '__main__': pytest.main([__file__])