129 lines
6.8 KiB
Python
Executable File
129 lines
6.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Legacy CPU plot regression: low and high real values on a fixed 0-100% axis.
|
|
|
|
Autoscaling was intentionally replaced by 0.33.5 fixed scaling. This test
|
|
retains the original history/reset and label checks using the current scale.
|
|
Chromium is simulated, not a live RustProxy server.
|
|
"""
|
|
from pathlib import Path
|
|
from panel_html import render_admin_index
|
|
import re
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
HTML = render_admin_index(ROOT)
|
|
CSS = (ROOT / 'src/admin/web/style.css').read_text(encoding='utf-8')
|
|
SCALE_JS = (ROOT / 'src/admin/web/app/chart-scales.js').read_text(encoding='utf-8')
|
|
WIDE_JS = (ROOT / 'src/admin/web/app/overview-wide-metrics.js').read_text(encoding='utf-8')
|
|
|
|
|
|
def inspect(page):
|
|
return page.evaluate('''() => {
|
|
const get = id => document.querySelector(`#dashboard-overview-grid [data-dashboard-widget="${id}"]`);
|
|
const cpu = get('wide_cpu'), cpuSvg = cpu.querySelector('svg');
|
|
const protocolSvg = get('wide_protocol_rates').querySelector('svg');
|
|
const backendSvg = get('backend_traffic').querySelector('svg');
|
|
const legend = cpu.querySelector('.overview-wide-legend').getBoundingClientRect();
|
|
const bounds = cpu.getBoundingClientRect();
|
|
const matrix = cpuSvg.getScreenCTM();
|
|
return {
|
|
cpuHeight: cpuSvg.getBoundingClientRect().height,
|
|
protocolHeight: protocolSvg.getBoundingClientRect().height,
|
|
backendHeight: backendSvg.getBoundingClientRect().height,
|
|
svgWidth: cpuSvg.getBoundingClientRect().width,
|
|
drawnWidth: Math.hypot(matrix.a, matrix.b) * cpuSvg.viewBox.baseVal.width,
|
|
ratio: cpuSvg.getAttribute('preserveAspectRatio'),
|
|
cpuSeries: cpuSvg.querySelectorAll('.overview-wide-series').length,
|
|
lineEffect: getComputedStyle(cpuSvg.querySelector('.overview-wide-series')).vectorEffect,
|
|
gridEffect: getComputedStyle(cpuSvg.querySelector('.chart-grid')).vectorEffect,
|
|
legendInCard: legend.top >= bounds.top && legend.bottom <= bounds.bottom + 1,
|
|
overflow: document.documentElement.scrollWidth - innerWidth,
|
|
};
|
|
}''')
|
|
|
|
|
|
def render_cpu(page, revision, system, process):
|
|
return page.evaluate('''({revision,system,process}) => {
|
|
window.rustProxyWideOverview.render({revision,live_system:{
|
|
cpu_percent:system, process_cpu_percent:process
|
|
}});
|
|
const read = name => {
|
|
const prefix = `overview-wide-wide_cpu-${name}`;
|
|
return {
|
|
path: document.getElementById(`${prefix}-line`).getAttribute('d'),
|
|
label: document.getElementById(`${prefix}-value`).textContent,
|
|
};
|
|
};
|
|
return {system:read('system'),process:read('process')};
|
|
}''', {'revision': revision, 'system': system, 'process': process})
|
|
|
|
|
|
def ys(path):
|
|
return [int(v) for v in re.findall(r'[ML]\d+\s+(\d+)', path)]
|
|
|
|
|
|
with sync_playwright() as p:
|
|
browser = p.chromium.launch(headless=True, executable_path='/usr/bin/chromium', args=['--no-sandbox'])
|
|
for viewport in (320, 375, 768, 1440, 1920):
|
|
page = browser.new_page(viewport={'width': viewport, 'height': 950})
|
|
errors = []
|
|
page.on('pageerror', lambda error: errors.append(str(error)))
|
|
page.set_content(HTML.replace('/assets/app___RUSTPROXY_ASSET_ID__.js', '')
|
|
.replace('/assets/style___RUSTPROXY_ASSET_ID__.css', ''))
|
|
page.add_style_tag(content=CSS)
|
|
page.evaluate('''() => {
|
|
document.documentElement.classList.remove('app-loading', 'app-startup-failed');
|
|
document.getElementById('workspace').hidden = false;
|
|
document.getElementById('panel-overview').hidden = false;
|
|
const grid = document.getElementById('dashboard-overview-grid');
|
|
grid.classList.add('is-aligned');
|
|
for (const card of grid.querySelectorAll(':scope > [data-dashboard-widget]')) {
|
|
card.hidden = !['wide_cpu', 'wide_protocol_rates', 'backend_traffic'].includes(card.dataset.dashboardWidget);
|
|
}
|
|
window.currentPanel = 'overview';
|
|
window.$ = id => document.getElementById(id);
|
|
window.fmt = (value, digits = 0) => Number(value).toFixed(digits);
|
|
window.fmtBytes = value => `${value} B`;
|
|
window.rustProxyOverviewSamples = {getLimit: () => 60, onChange: () => {}};
|
|
}''')
|
|
page.add_script_tag(content=SCALE_JS)
|
|
page.add_script_tag(content=WIDE_JS)
|
|
|
|
for density in ('compact', 'normal', 'ultra'):
|
|
page.evaluate('(density) => document.documentElement.dataset.dashboardDensity = density', density)
|
|
result = inspect(page)
|
|
assert result['protocolHeight'] >= 124, (viewport, density, result)
|
|
assert abs(result['cpuHeight'] - result['protocolHeight']) <= 1, (
|
|
'CPU must use standard chart height', viewport, density, result)
|
|
assert result['backendHeight'] > 0, (viewport, density, result)
|
|
assert result['ratio'] == 'none' and result['cpuSeries'] == 2, result
|
|
assert result['lineEffect'] == result['gridEffect'] == 'non-scaling-stroke', result
|
|
assert result['svgWidth'] > 100 and abs(result['svgWidth'] - result['drawnWidth']) < 2, result
|
|
assert result['legendInCard'] and result['overflow'] <= 2, (viewport, density, result)
|
|
|
|
# Measured 0.5-0.8% stay numerically visible without axis auto-expansion.
|
|
first = render_cpu(page, 1, 0.5, 0.2)
|
|
second = render_cpu(page, 1, 0.8, 0.6)
|
|
assert first['system']['label'] == '0.5%' and second['process']['label'] == '0.6%'
|
|
assert ys(second['system']['path']) == [136, 136], (viewport, second)
|
|
assert ys(second['process']['path']) == [137, 136], (viewport, second)
|
|
|
|
# Multi-core values display accurately but clip at the fixed 100% ceiling.
|
|
third = render_cpu(page, 1, 3.4, 2.2)
|
|
assert ys(third['system']['path'])[-1] == 133, (viewport, third)
|
|
assert ys(third['process']['path'])[-1] == 134, (viewport, third)
|
|
high = render_cpu(page, 1, 250, 123)
|
|
assert high['system']['label'] == '250.0%'
|
|
assert ys(high['system']['path'])[-1] == 17, (viewport, high)
|
|
assert ys(high['process']['path'])[-1] == 17, (viewport, high)
|
|
|
|
# Revision changes reset the history. Zero stays at the plot baseline.
|
|
idle = render_cpu(page, 2, 0, 0)
|
|
assert ys(idle['system']['path']) == [137] and ys(idle['process']['path']) == [137]
|
|
missing = render_cpu(page, 3, None, None)
|
|
assert missing['system']['path'] == '' and missing['process']['label'] == '-'
|
|
assert not errors, (viewport, errors)
|
|
print(f'PASS legacy CPU labels/history on fixed Y-scale at {viewport}px (all densities)')
|
|
page.close()
|
|
browser.close()
|