#!/usr/bin/env python3 """Simulated Web Server telemetry against the production admin JS/CSS bundle. Browser-only test: does not assert live RustProxy, PHP-FPM, or network behavior. Run: python3 scripts/tests/web_server_0330_ui_test.py """ from __future__ import annotations import json from pathlib import Path import re from playwright.sync_api import sync_playwright ROOT = Path(__file__).resolve().parents[2] router = (ROOT / 'src/admin/router.rs').read_text() match = re.search(r'fn admin_app_javascript\([^)]*\)[^{]*\{', router) assert match, 'admin_app_javascript definition missing' portion = router[match.end():] portion = portion[:re.search(r'\]\s*\.join\("\\n"\)', portion).start()] fragments = [] for line in portion.splitlines(): line = line.strip() if 'include_str!("' in line: path = re.search(r'include_str!\("([^"]+)"\)', line).group(1) fragments.append((ROOT / 'src/admin' / path).read_text()) elif line == 'admin_vhosts_javascript(),': fragments.append('(() => {\n' + '\n'.join((ROOT / 'src/admin/web/vhosts' / f'{part}.js').read_text() for part in ['core', 'protocol', 'health', 'rates', 'editor', 'render']) + '\n})();') elif line.startswith('"') and line.endswith('",'): fragments.append(json.loads(line[:-1])) BUNDLE = '\n'.join(fragments) assert BUNDLE.index('window.rustProxyOverviewSamples =') < BUNDLE.index('window.rustProxyOverviewSamples.onChange(') WEB = { 'requests': 100, 'status_2xx': 90, 'status_3xx': 2, 'status_4xx': 5, 'status_5xx': 3, 'response_headers_us': 2_500_000, 'response_bytes': 10_000, 'active_headers': 2, 'static_requests': 70, 'php_requests': 25, 'other_requests': 5, 'methods': [80, 10, 5, 2, 3], 'selected_status': [75, 5, 2, 0, 5, 1, 1, 1], 'failures': [0] * 9, 'compression': [5, 3, 2, 1], } PHP = { 'requests': 25, 'status_2xx': 22, 'status_3xx': 0, 'status_4xx': 1, 'status_5xx': 2, 'response_headers_us': 1_000_000, 'response_bytes': 2_000, 'failures': [1, 2, 3, 4, 5, 6, 7, 8, 9], } def observation(factor: int): web = {key: ([factor * v for v in value] if isinstance(value, list) else factor * value) for key, value in WEB.items()} php = {key: ([factor * v for v in value] if isinstance(value, list) else factor * value) for key, value in PHP.items()} web['active_headers'] = 2 return {'revision': 10, 'web_server_metrics': { 'site-A': {'web': web, 'php': {'metrics': php, 'capacity_limit': 32, 'capacity_used': 18}} }} with sync_playwright() as p: browser = p.chromium.launch(headless=True, executable_path='/usr/bin/chromium', args=['--no-sandbox']) for width in (320, 375, 800, 1440): page = browser.new_page(viewport={'width': width, 'height': 900}) errors = [] page.on('pageerror', lambda err: errors.append(str(err))) page.set_content((ROOT / 'src/admin/web/index.html').read_text()) page.add_style_tag(content=(ROOT / 'src/admin/web/style.css').read_text()) page.add_script_tag(content=BUNDLE) page.evaluate("""() => { document.querySelector('#workspace').hidden = false; document.querySelector('#panel-overview').hidden = false; document.querySelectorAll('[data-dashboard-widget^="www_"]').forEach(n => n.hidden = false); currentPanel = 'overview'; window.__clock = 1000; Object.defineProperty(performance, 'now', { configurable: true, value: () => window.__clock }); }""") first, second = observation(1), observation(2) state = page.evaluate("""([one, two]) => { const api = window.rustProxyWebOverview; api.render(one); window.__clock = 4000; api.render(two); return { rps: document.getElementById('www_requests-all-value').textContent, php: document.getElementById('www_requests-php-value').textContent, latency: document.getElementById('www_latency-web-value').textContent, capacity: document.getElementById('www_capacity-value').textContent, types: document.getElementById('www_kind-value').textContent, status: document.getElementById('www_status-value').textContent, bytes: document.getElementById('www_traffic-value').textContent, top: document.getElementById('www_top_services-value').textContent, layoutWidth: document.documentElement.scrollWidth, screenWidth: window.innerWidth, children: document.querySelectorAll('[data-dashboard-widget^="www_"]').length, sampleCount: document.getElementById('www_requests-all-line').getAttribute('d'), limit: window.rustProxyOverviewSamples.getLimit(), }; }""", [first, second]) assert state['children'] == 12, state assert state['rps'] != '-' and state['php'] != '-', state assert 'ms' in state['latency'] and '18' in state['capacity'], state assert state['types'].endswith('%') and state['status'].endswith('%'), state assert '/s' in state['top'], state assert state['layoutWidth'] <= state['screenWidth'] + 2, (width, state) assert not errors, (width, errors) # Exercise the Web Server per-service accordion with the same status, # without any real HTTP/PHP request or extra polling. details = page.evaluate("""(status) => { envelope = { revision: 10, config: { web_services: [{ id: 'site-A', name: 'Example', document_root: '/var/www/site-A', index: ['index.html'], php: { enabled: true } }], vhosts: [], php_fpm_profiles: [] }}; currentPanel = 'web-server'; window.rustProxyWebServer.render(); const detail = document.querySelector('#web-service-list .www-service-panel'); if (!detail) return { missing: true }; detail.open = true; window.rustProxyWebServer.renderLive(status, false); return { text: detail.textContent, rows: detail.querySelectorAll('[data-web-live-field]').length }; }""", second) assert not details.get('missing') and details['rows'] == 7, (width, details) assert '18 / 32' in details['text'], (width, details) assert not errors, (width, errors) old = page.evaluate("""() => { currentPanel = 'overview'; window.rustProxyWebOverview.render({ revision: 11, web_server_metrics: {} }); return { rate: document.getElementById('www_requests-value').textContent, status: document.getElementById('www_status-value').textContent, top: document.getElementById('www_top_services-bars').childElementCount, }; }""") assert old == {'rate': '-', 'status': '-', 'top': 0}, (width, old) assert not errors, (width, errors) print(f'PASS simulated Web Server cards and service accordion at {width}px: {state["rps"]}, {state["php"]}, layout {state["layoutWidth"]}px') page.close() browser.close() print('PASS production JS bundle + all twelve visible WWW widgets (simulated data only)')