Files
RustProxy/scripts/tests/web_observability_0330_source_test.py
T
2026-10-15 09:37:47 +02:00

84 lines
4.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""Static contracts for 0.33.0 WWW observability (not Rust compilation)."""
from pathlib import Path
import json
import re
import tomllib
ROOT = Path(__file__).resolve().parents[2]
read = lambda file: (ROOT / file).read_text()
manifest = tomllib.loads(read('Cargo.toml'))
lock = tomllib.loads(read('Cargo.lock'))
version = manifest['package']['version']
assert version == '0.33.0'
assert [p['version'] for p in lock['package'] if p['name'] == 'rust-proxy'] == [version]
registry = json.loads(read('src/admin/web/dashboard-widgets.json'))
widgets = [w for w in registry if w['id'].startswith('www_')]
assert len(widgets) == 12
assert all(w['default_hidden'] is True for w in widgets)
assert len({w['id'] for w in registry}) == len(registry)
html = read('src/admin/web/index.html')
english = json.loads(read('langs/en_US.json'))['translations']
polish = json.loads(read('langs/pl_pl.json'))['translations']
for widget in widgets:
assert f'data-dashboard-widget="{widget["id"]}" hidden' in html, widget['id']
assert widget['label_key'] in english, widget['label_key']
assert widget['label_key'] in polish, widget['label_key']
if widget['description_key']:
assert widget['description_key'] in english
assert widget['description_key'] in polish
# Safely assemble the admin app before core.js: the earlier release crashed on
# registering onChange callbacks before rustProxyOverviewSamples was defined.
router = read('src/admin/router.rs')
assert router.index('include_str!("web/app/overview-samples.js")') < router.index('include_str!("web/app/core.js")')
assert '"web/app/web-overview.js"' in router
assert '"web_server_metrics"' in read('src/admin/status_live.rs')
assert 'web_server_metrics_payload(&snapshot)' in read('src/admin/status.rs')
# record_web is only consumed by web_server::serve; expose no wider than the
# ResponseKind enum argument. This is a static visibility contract, not rustc.
metrics = read('src/web_server/metrics.rs')
assert 'pub(super) enum ResponseKind' in metrics
assert 'pub(super) fn record_web(' in metrics
assert 'pub(crate) fn record_web(' not in metrics
assert 'service.web_metrics.record_web(' in read('src/web_server/serve.rs')
families = read('src/prometheus/web_php.rs')
required = {
'rust_proxy_web_server_requests_total', 'rust_proxy_web_server_responses_total',
'rust_proxy_web_server_request_kind_total', 'rust_proxy_web_server_methods_total',
'rust_proxy_web_server_status_code_total', 'rust_proxy_web_server_response_header_duration_microseconds_total',
'rust_proxy_web_server_response_body_bytes_total', 'rust_proxy_web_server_requests_active',
'rust_proxy_web_server_compression_total', 'rust_proxy_php_requests_total',
'rust_proxy_php_responses_total', 'rust_proxy_php_response_header_duration_microseconds_total',
'rust_proxy_php_response_body_bytes_total', 'rust_proxy_php_concurrency_available',
'rust_proxy_php_concurrency_limit', 'rust_proxy_php_concurrency_in_use', 'rust_proxy_php_failures_total'
}
assert all(f'"{name}"' in families for name in required), required
assert 'PHP_FAILURE_NAMES' in families
assert re.search(r'\["GET", "POST", "PUT", "DELETE", "other"\]', families)
assert 'let wl = labels(&[("web_service", service.id.as_str())]);' in families
j = json.loads(read('grafana/rustproxy-overview.json'))
assert j['title'].startswith('RustProxy 0.33.0')
ids = [p['id'] for p in j['panels']]
assert len(ids) == len(set(ids))
assert any(v.get('name') == 'web_service' and v.get('multi') and v.get('includeAll') for v in j['templating']['list'])
for title in ('Web Server 0.33.0', 'PHP-FPM / FastCGI', 'Per Web Service', 'WWW / PHP correlation'):
assert any(p['title'] == title and p['type'] == 'row' for p in j['panels'])
extra = [p for p in j['panels'] if p['id'] >= 89]
for i, p in enumerate(extra):
a = p['gridPos']
assert 0 <= a['x'] and a['w'] > 0 and a['x'] + a['w'] <= 24
for q in extra[i + 1:]:
b = q['gridPos']
overlap = a['x'] < b['x'] + b['w'] and b['x'] < a['x'] + a['w'] and a['y'] < b['y'] + b['h'] and b['y'] < a['y'] + a['h']
assert not overlap, (p['id'], q['id'])
production = [p for p in (ROOT / 'src').rglob('*.rs') if p.name != 'tests.rs' and 'tests' not in p.parts]
large = [str(p.relative_to(ROOT)) for p in production if len(p.read_text().splitlines()) > 500]
assert not large, large
print('PASS RustProxy 0.33.0 source version, opt-in widgets, localizations, status API,')
print(' exporter families, Grafana geometry/filtering and Rust module size (STATIC ONLY)')