Files
harbor-net/test/web/prometheus-instructions.test.js
T
dokril 837f058025
Build and Deploy Gateway / build-and-push (push) Successful in 14s
Build and Deploy Gateway / deploy (push) Successful in 7s
Configure symlog scaling for gateway traffic dashboard
2026-08-08 08:09:47 +03:00

102 lines
6.7 KiB
JavaScript

import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import test from 'node:test';
const root = path.resolve(import.meta.dirname, '../..');
const overview = fs.readFileSync(path.join(root, 'src/web/components/ClientOverviewPage.jsx'), 'utf8');
const instructions = fs.readFileSync(path.join(root, 'src/web/instructions.js'), 'utf8');
const prometheus = fs.readFileSync(path.join(root, 'src/web/prometheus.js'), 'utf8');
const server = fs.readFileSync(path.join(root, 'src/server/index.js'), 'utf8');
const styles = fs.readFileSync(path.join(root, 'src/web/styles.css'), 'utf8');
const dashboard = JSON.parse(fs.readFileSync(path.join(root, 'monitoring/grafana/harbor-gateway.json'), 'utf8'));
test('Gateway info drawer contains copyable Prometheus and Grafana instructions', () => {
assert.match(instructions, /\.\.\.\(isGateway \? \[\{/);
assert.match(instructions, /id: 'prometheus'/);
assert.match(instructions, /title: 'Prometheus и Grafana'/);
assert.match(instructions, /prometheusScrapeConfig\(controlHost\)/);
assert.match(instructions, /label: 'prometheus\.yml'/);
assert.match(instructions, /label: 'Grafana dashboard'/);
assert.match(prometheus, /monitoring\/grafana\/harbor-gateway\.json/);
assert.match(prometheus, /scrape_interval: 30s[\s\S]*metrics_path: \/metrics/);
assert.match(overview, /const controlHost = window\.location\.host/);
assert.match(overview, /client-copy-label">Скопировать/);
assert.doesNotMatch(overview, /prometheus-toggle|Prometheus<\/span><\/button>/);
assert.match(styles, /\.client-instruction-copy-button \{[\s\S]*width: 104px;[\s\S]*min-width: 104px/);
assert.match(styles, /@media \(prefers-reduced-motion: reduce\)[\s\S]*\.client-copy-feedback/);
});
test('metrics route reads the current snapshot before static fallback', () => {
const metricsRoute = server.indexOf("requestUrl.pathname === '/metrics'");
const staticFallback = server.indexOf(': serveStatic(req, res)');
assert.ok(metricsRoute >= 0 && metricsRoute < staticFallback);
assert.match(server, /requestUrl\.pathname === '\/metrics'[\s\S]*deviceInventory\.metricsSnapshot\(\)/);
assert.doesNotMatch(server.slice(metricsRoute, staticFallback), /deviceInventory\.refresh\(/);
});
test('Grafana dashboard uses one all-or-one device scope and shows active device speed', () => {
const expressions = dashboard.panels.flatMap((panel) => panel.targets || []).map(({ expr }) => expr).filter(Boolean);
const titles = dashboard.panels.map(({ title }) => title);
const deviceVariable = dashboard.templating.list[0];
const freshness = dashboard.panels.find(({ id }) => id === 2);
const globalSpeed = dashboard.panels.find(({ id }) => id === 3);
const topDevices = dashboard.panels.find(({ id }) => id === 5);
const sourceSpeed = dashboard.panels.find(({ id }) => id === 6);
const deviceSpeed = dashboard.panels.find(({ id }) => id === 14);
const services = dashboard.panels.find(({ id }) => id === 8);
const domains = dashboard.panels.find(({ id }) => id === 9);
assert.equal(dashboard.title, 'Harbor Gateway: трафик');
assert.equal(dashboard.refresh, '30s');
assert.deepEqual(titles.filter((title) => ['Обзор', 'Устройства', 'Сервисы и домены', 'Техническая детализация'].includes(title)), [
'Обзор',
'Устройства',
'Сервисы и домены',
'Техническая детализация',
]);
assert.ok(titles.includes('Скорость сейчас, средняя за 5 минут'));
assert.ok(titles.includes('Скорость по устройствам сейчас'));
assert.ok(titles.includes('Скорость по источникам и направлениям сейчас'));
assert.ok(titles.includes('Топ-10 устройств за выбранный период'));
assert.ok(titles.includes('Накоплено по источникам и направлениям'));
assert.ok(titles.includes('Сервисы за выбранный период'));
assert.ok(titles.includes('Домены за выбранный период'));
assert.ok(expressions.some((expression) => expression.includes('harbor_traffic_bytes_total')));
assert.ok(expressions.some((expression) => expression.includes('harbor_device_traffic_bytes_total')));
assert.ok(expressions.some((expression) => expression.includes('harbor_device_domain_traffic_bytes_total{device_id=~"$device_id"}[$__range]')));
assert.ok(expressions.some((expression) => expression.includes('harbor_domain_traffic_last_observed_timestamp_seconds')));
assert.match(topDevices.targets[0].expr, /^topk\(10,[\s\S]*increase\(harbor_device_traffic_bytes_total\[\$__range\]\)[\s\S]*> 0[\s\S]*group_left \(name, ip\)/);
assert.equal(topDevices.options.sortBy[0].desc, true);
assert.match(topDevices.fieldConfig.overrides[1].properties[0].value[0].url, /var-device_id=\$\{__data\.fields/);
assert.doesNotMatch(topDevices.fieldConfig.overrides[1].properties[0].value[0].url, /domain_device_id/);
assert.deepEqual(freshness.fieldConfig.defaults.thresholds.steps.map(({ value }) => value), [null, 60, 120]);
assert.equal(freshness.fieldConfig.defaults.noValue, 'Нет данных');
assert.equal(deviceVariable.name, 'device_id');
assert.equal(deviceVariable.multi, false);
assert.equal(deviceVariable.includeAll, true);
assert.equal(deviceVariable.allValue, '.*');
assert.equal(deviceVariable.current.value, '$__all');
assert.equal(dashboard.templating.list.length, 1);
assert.match(deviceVariable.query.query, /query_result\(label_join\(/);
assert.match(deviceVariable.regex, /<text>/);
assert.match(deviceVariable.regex, /<value>/);
assert.ok(globalSpeed.targets.every(({ expr }) => expr.includes('device_id=~"$device_id"') && expr.endsWith('> 0')));
assert.match(deviceSpeed.targets[0].expr, /sum by \(device_id\)[\s\S]*device_id=~"\$device_id"[\s\S]*> 0[\s\S]*group_left \(name, ip\)/);
assert.match(deviceSpeed.targets[0].legendFormat, /\{\{name\}\} · \{\{ip\}\}/);
assert.deepEqual(deviceSpeed.fieldConfig.defaults.custom.scaleDistribution, {
linearThreshold: 1048576,
log: 2,
type: 'symlog',
});
assert.match(sourceSpeed.targets[0].expr, /device_id=~"\$device_id"[\s\S]*> 0$/);
assert.match(services.targets[0].expr, /device_id=~"\$device_id"[\s\S]*> 0\)$/);
assert.deepEqual(domains.transformations[0].options.indexByName, { service: 0, domain: 1, Value: 2 });
assert.match(domains.targets[0].expr, /^topk\(15,[\s\S]*device_id=~"\$device_id"[\s\S]*> 0\)$/);
assert.ok(dashboard.panels
.filter(({ type }) => ['bargauge', 'table'].includes(type))
.flatMap(({ targets }) => targets || [])
.every(({ expr }) => expr.includes('> 0')));
});