2026-09-03 16:40:18 +02:00
|
|
|
import http.client
|
2026-09-03 23:20:47 +02:00
|
|
|
import json
|
2026-09-03 16:40:18 +02:00
|
|
|
import os
|
|
|
|
|
import threading
|
|
|
|
|
import unittest
|
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
|
|
from server import ProxyStaticHandler
|
2026-09-03 23:20:47 +02:00
|
|
|
from http.server import ThreadingHTTPServer
|
|
|
|
|
|
|
|
|
|
RealHTTPConnection = http.client.HTTPConnection
|
2026-09-03 16:40:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
2026-09-03 23:20:47 +02:00
|
|
|
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)
|
|
|
|
|
|
2026-09-03 16:40:18 +02:00
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
unittest.main()
|