diff --git a/app/(main)/uptime/page.tsx b/app/(main)/uptime/page.tsx index 5fc62d04..57c6a018 100644 --- a/app/(main)/uptime/page.tsx +++ b/app/(main)/uptime/page.tsx @@ -1664,12 +1664,12 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId lines.push("") if (si) { - lines.push(`/ip address print where name="${si.replace(/"/g, '\\"')}"`) + lines.push(`/ip address print where interface="${si.replace(/"/g, '\\"')}"`) lines.push("") } if (di) { lines.push(`# Выполнить на узле назначения (${dst.name}) — адрес приёмника BT-сервера:`) - lines.push(`/ip address print where name="${di.replace(/"/g, '\\"')}"`) + lines.push(`/ip address print where interface="${di.replace(/"/g, '\\"')}"`) lines.push("") } @@ -2778,6 +2778,11 @@ function UptimePageContent({ selectedProbeId, allProbesHref }: { selectedProbeId /> +

+ Интерфейс источника используется для Ping после теста. На назначении выбирается + IP интерфейса, статический — первым. Маршрут bandwidth-test определяет RouterOS. +

+
=400, HTTP-моков нет. Temporaryfrontend/backend/network/3018 закрыты, destinationhost восстановлен и проверен, testprobes0; основной стенд/туннель сохранены. Локальная regression31s/TypeScript/ESLint12.5.26 и real production browser proof подтверждают исправление proxy. ROS-2 transport timeout принят в этих границах; native can not connect/busy/disconnect/abort и Portal/multi-instance остаются открытыми. Следующий12.5.28 — ROS-3: фактический адрес native bandwidth-test и интерфейс after-ping. План/паспорт/протокол обновлены; локальный коммит без push. + +## 12.5.28 — интерфейс bandwidth-test и after-ping; уточнение формы (2026-10-08) + +[Real native/API/SQL evidence](ux-ui/acceptance/speed-interface-2026-10-08.json): backend8782054, выделенная mmapp_acceptance_20261007; реальные inventory и команды, HTTP/RouterOS-моков нет. На обоих CHR активны ether1/lo. НаCHR1 ether1 имеет dynamic194.226.121.150/24; наCHR2 dynamic104.165.244.7/24 иstatic195.195.195.195/32. Существующая конфигурация RouterOS не менялась. API каталога предпочитает static195 при явном выборе ether1 назначения. Это не тот же адрес, что host/API104. + +Три попытки1→2 (дважды с выбранным ether1 назначения, один разauto) получили502/transport timeout и historyerror; никакая из них не объявлена успешной. Bandwidth-server enabledtrue/authenticatetrue/maxsessions100 наобоихCHR, Ping1→2 и2→1 поether1 подтвердил2/2/0%loss. Причина timeout1→2/auto не установлена. Нельзя заключать, что её вызвала ошибка приложения или исключительноstaticадрес. + +Отдельная принятая команда2→1: srcInterfaceether1, dstInterfaceauto, TCPtransmit3s/HTTP200. Wrapper считал и записывал только несекретные параметры настоящих вызовов: bandwidth address194.226.121.150 без interface-параметра; after-ping addressтотже/count4/interfaceether1/interval1s. API/SQLhistorydone, TX3756.788128/RXnull, Ping53ms/0%loss. srcInterfaceAddress195 — metadata выбранного интерфейса, не доказательство фактического source IP bandwidth packets. Native routing определяет RouterOS; source-interface binding не реализован. В принятом прогоне native1, всего4 команды с учётом трёх непрошедшихforward-прогонов. Это функциональная проверка, не benchmark/multi-WAN proof. + +В форме локально добавлено пояснение: интерфейс источника используется для Ping после теста, интерфейс назначения выбираетIP/staticfirst, маршрутbandwidth-test определяетRouterOS. Исправлена CLI-подсказка /ip address print where interface= вместоwhere name=; [синтаксис RouterOS](https://help.mikrotik.com/docs/spaces/ROS/pages/47579229/Scripting). Установленные ReUI/Frame-композиции сохранены, новый компонент не устанавливался. + +Проверки локального UI: uptime-speed-interface.spec.ts1/1 сHTTP-фикстурами — открытие формы, приоритет адреса изAPI, корректныйCLI/Ping, пояснение и320px fits; scopedfrontend TypeScript/ESLint passed. Это локальная проверка формы, не realbrowserproof новых текстов. Runtimefrontendaa7dbdf прежний, новыеUIизменения ещё не развёрнуты. + +Временные --rm containers закрыты, testprobes0; история тестов только в выделеннойБД, основнаяhistory5/backend8782054healthok сохранены. ROS-3 принят дляобратнойкоманды в перечисленных границах; forward2interface/auto не принят. Следующий12.5.29 — realbrowserform/deploymentподсказок; forward-native диагностика иполный12.5 остаются открытыми. План/паспорт/протокол обновлены, локальный коммит без push. diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index 81f427f1..e96fa018 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -157,3 +157,7 @@ ssh -N -L 3000:127.0.0.1:3000 -L 8000:127.0.0.1:8000 root@161.104.46.222 ## Новый frontend proxy timeout — 2026-10-08 12.5.27 [real browser timeout502](ux-ui/acceptance/speed-unreachable-error-2026-10-08.json), [frontend deployment](ux-ui/acceptance/deployed-frontend-aa7dbdf-2026-10-08.json), [пять экранов](ux-ui/acceptance/deploy-browser-aa7dbdf-2026-10-08.json) passed. Frontendaa7dbdf/proxy180s, backend8782054healthy прежний; MMAPP_IMAGE_TAG=ux-aa7dbdf/BACKEND_IMAGE_TAG=ux-8782054. Основной DBcontrol совпал. Isolatedhost/probe восстановлены/удалены, temporarycontainers/network/3018 закрыты. Это transport timeout, не native can not connect; техническая подпись timeout остаётся ограничением UX. Следующий12.5.28 — ROS-3 interface/address/after-ping. + +## Интерфейс native test и Ping — 2026-10-08 + +12.5.28 [real ROS-3](ux-ui/acceptance/speed-interface-2026-10-08.json): reverse2→1 done, bandwidth194.226.121.150/nointerfacebinding, Pingether1/0%loss; metadata source195 не доказываетsourceIPpackets. CHR2 имеет dynamic104/static195, явныйdstinterface предпочитаетstatic. Три1→2 попыткиtimeout, причинаauto-path не установлена; они не приняты. КонфигурацияRouterOS не менялась. Основнойruntimebackend8782054/frontendaa7dbdf/history5 сохранён. UIhint/CLIwhereinterface исправлены локально; browserfixture/typecheck/ESLint passed, не развёрнуты. Следующий12.5.29 — real browserform/deploymentподсказок. diff --git a/docs/ux-ui/acceptance/speed-interface-2026-10-08.json b/docs/ux-ui/acceptance/speed-interface-2026-10-08.json new file mode 100644 index 00000000..3e02e84d --- /dev/null +++ b/docs/ux-ui/acceptance/speed-interface-2026-10-08.json @@ -0,0 +1,138 @@ +{ + "date": "2026-10-08", + "backendSource": "8782054078304f36cc611876af2d17f87b857f60", + "database": "mmapp_acceptance_20261007", + "httpMocks": false, + "routerOsMocks": false, + "inventory": [ + { + "id": 1, + "host": "194.226.121.150", + "interfaces": [ + "ether1", + "lo" + ], + "addresses": [ + { + "interface": "ether1", + "address": "194.226.121.150/24", + "dynamic": "true" + } + ] + }, + { + "id": 2, + "host": "104.165.244.7", + "interfaces": [ + "ether1", + "lo" + ], + "addresses": [ + { + "interface": "ether1", + "address": "104.165.244.7/24", + "dynamic": "true" + }, + { + "interface": "ether1", + "address": "195.195.195.195/32", + "dynamic": "false" + } + ] + } + ], + "selectedDestination": { + "preferredStaticAddress": "195.195.195.195", + "earlierForwardTests": "timeout" + }, + "httpStatus": 200, + "nativeCount": 1, + "bandwidth": { + "address": "194.226.121.150", + "protocol": "tcp", + "direction": "transmit", + "durationSec": 3, + "hasInterfaceParameter": false + }, + "pingCalls": [ + { + "address": "194.226.121.150", + "count": 4, + "interface": "ether1", + "interval": "1s" + } + ], + "result": { + "runId": "acceptance-interface-1791428239785", + "srcInterfaceAddress": "195.195.195.195", + "dstInterfaceAddress": null, + "afterBtPing": { + "rttMs": 53, + "lossPct": 0, + "error": null + } + }, + "history": [ + { + "id": "acceptance-interface-1791428239785", + "src_interface": "ether1", + "dst_interface": "", + "src_interface_address": "195.195.195.195", + "dst_interface_address": null, + "status": "done", + "tx_avg_mbps": 3756.7881279999997, + "rx_avg_mbps": null, + "ping_rtt_ms": 53, + "ping_loss_pct": 0 + } + ], + "limits": [ + "Bandwidth routing chosen by RouterOS, no source-interface binding", + "One actual interface per CHR; multi-WAN route selection not tested", + "Accepted reverse command1; three earlier forward attempts timed out, forward path remains unaccepted", + "API/SQL/native proof; browser form not tested in this block" + ], + "firstInventoryAddresses": [ + { + "interface": "ether1", + "address": "194.226.121.150" + }, + { + "interface": "ether1", + "address": "104.165.244.7" + } + ], + "acceptedContext": { + "srcServerId": 2, + "dstServerId": 1, + "srcInterface": "ether1", + "dstInterface": "auto" + }, + "forwardAttempts": [ + { + "id": "acceptance-interface-1791427768086", + "srcInterface": "ether1", + "dstInterface": "ether1", + "status": "error" + }, + { + "id": "acceptance-selected-destination-1791428012326", + "srcInterface": "ether1", + "dstInterface": "ether1", + "status": "error" + }, + { + "id": "acceptance-interface-1791428042466", + "srcInterface": "ether1", + "dstInterface": "auto", + "status": "error" + } + ], + "cleanup": { + "testProbesRemaining": 0, + "temporaryContainersRemoved": true, + "mainHistoryCountUnchanged": 5, + "mainHealth": "ok", + "mainBackendVersion": "1.0.0-test.8782054" + } +} diff --git a/tests/e2e/uptime-speed-interface.spec.ts b/tests/e2e/uptime-speed-interface.spec.ts new file mode 100644 index 00000000..a3daa4d3 --- /dev/null +++ b/tests/e2e/uptime-speed-interface.spec.ts @@ -0,0 +1,30 @@ +import { test, expect } from "@playwright/test" +import { server } from "./fixtures/users" + +test("Speed: форма использует адрес каталога и разделяет маршрут теста и Ping-интерфейс", async ({ page }) => { + const probe = { id: "iface-probe", srcServerId: "1", dstServerId: "2", srcInterface: "ether1", dstInterface: "ether1", protocol: "tcp", direction: "transmit", durationSec: "3", enabled: true, lastRunAt: null, lastStatus: null, lastError: null, lastTxAvgMbps: null, lastRxAvgMbps: null } + await page.route("**/health", route => route.fulfill({ json: { ok: true } })) + await page.route("**/api/**", route => { + const path = new URL(route.request().url()).pathname + return route.fulfill({ json: + path === "/api/auth/config" ? { required: false } : + path === "/api/servers" ? [server, { ...server, id: 2, name: "Назначение", host: "198.51.100.2" }] : + path === "/api/uptime/overview" ? { probes: [], resources: [] } : + path === "/api/uptime/speed-probes" ? { probes: [probe] } : + path === "/api/uptime/speed-test/runs" ? { runs: [] } : + path.includes("/speed-test/endpoints/") ? { interfaces: [{ name: "ether1", running: true, disabled: false, addresses: path.includes("/2/") ? ["195.195.195.195", "198.51.100.2"] : ["192.0.2.1"] }] } : {}, + }) + }) + await page.goto("/uptime?tab=speed") + await page.getByRole("button", { name: "Редактировать speed-пробу", exact: true }).click() + const dialog = page.getByRole("dialog") + const commands = dialog.locator("pre") + await expect(commands).toContainText('/ip address print where interface="ether1"') + await expect(commands).not.toContainText("where name=") + await expect(commands).toContainText('/ping address=195.195.195.195 count=4 interface="ether1"') + await expect(commands).toContainText("/tool bandwidth-test address=195.195.195.195") + await expect(dialog).toContainText("Интерфейс источника используется для Ping после теста") + await expect(dialog).toContainText("Маршрут bandwidth-test определяет RouterOS") + await page.setViewportSize({ width: 320, height: 900 }) + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true) +})