import http.client import json import os import threading import unittest from unittest.mock import patch from server import ProxyStaticHandler from http.server import ThreadingHTTPServer RealHTTPConnection = http.client.HTTPConnection class FakeUpstream: def __init__(self, *args, **kwargs): self.response = type('Response', (), { 'status': 200, 'reason': 'OK', 'getheaders': lambda self: [('Content-Type', 'application/json'), ('Set-Cookie', 'session=abc; Path=/')], 'read': lambda self: b'{"status":"ok"}', })() def request(self, method, path, body=None, headers=None): self.method, self.path, self.body, self.headers = method, path, body, headers def getresponse(self): return self.response def close(self): pass class ProxyServerTests(unittest.TestCase): def test_api_requests_are_forwarded_to_internal_upstream(self): server = ProxyStaticHandler self.assertTrue(hasattr(server, 'proxy_api')) with patch('server.http.client.HTTPConnection', FakeUpstream): self.assertTrue(server.proxy_api) def test_upstream_failure_is_structured_json(self): httpd = ThreadingHTTPServer(("127.0.0.1", 0), ProxyStaticHandler) thread = threading.Thread(target=httpd.serve_forever, daemon=True) thread.start() try: with patch('server.http.client.HTTPConnection', side_effect=OSError('connection refused')): conn = RealHTTPConnection('127.0.0.1', httpd.server_port, timeout=3) conn.request('GET', '/api/v1/dashboard/summary') response = conn.getresponse() body = response.read() self.assertEqual(response.status, 502) self.assertEqual(response.getheader('Content-Type'), 'application/json; charset=utf-8') self.assertEqual(json.loads(body), {'error': 'api_upstream_unavailable'}) finally: httpd.shutdown(); httpd.server_close(); thread.join(timeout=2) if __name__ == '__main__': unittest.main()