Files
MikrotikManager/tests/e2e/ospf-operations.spec.ts
T

99 lines
6.8 KiB
TypeScript

import { test, expect } from "@playwright/test"
const device = { id: 1, name: "Роутер 1", host: "192.0.2.1", enabled: true, country: "RU", status: null }
const iface = { id: "*1", serverId: 1, serverName: "Роутер 1", serverSite: "", serverCountry: "RU", instance: "default", area: "backbone", areaId: "0.0.0.0", interface: "ether1", cost: 20, type: "broadcast", disabled: false, inactive: false, priority: 1, helloInterval: 10, deadInterval: 40, useBfd: false }
const catalog = { neighbors: [], interfaces: [iface], instances: [], bfdSessions: [], routes: [], failures: [] }
const result = { serverId: 1, serverName: "Роутер 1", pingWeight: 60, optimizedCount: 1, applied: [{ interface: "ether1", from: 20, to: 10 }], interfaces: [{ id: "*1", interface: "ether1", currentCost: 20, optimalCost: 10, score: 1, pingMs: 10, dlMbps: 100, ulMbps: 100 }] }
for (const outcome of ["success", "http", "foreign", "malformed", "poll-failure"]) {
test("OSPF: оптимизация, общий lock и результат " + outcome, async ({ page }) => {
let writes = 0, polled = false, reads = 0
let release: (() => void) | undefined
const gate = new Promise<void>(resolve => { release = resolve })
await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
await page.route("**/api/**", async r => {
const path = new URL(r.request().url()).pathname
if (path === "/api/servers/1/ospf/optimize") {
writes++
expect(r.request().method()).toBe("POST")
expect(r.request().postDataJSON().pingWeight).toBeGreaterThanOrEqual(0)
await gate
polled = true
return r.fulfill(outcome === "http" ? { status: 503, json: { error: "Применение не завершено" } } : { json: outcome === "foreign" ? { ...result, serverId: 2 } : outcome === "malformed" ? { ...result, optimizedCount: 99 } : result })
}
if (path === "/api/ospf/catalog") {
reads++
if (polled && outcome === "poll-failure") return r.fulfill({ status: 503, json: { error: "Опрос после записи недоступен" } })
return r.fulfill({ json: catalog })
}
return r.fulfill({ json: path === "/api/servers" ? [device] : path === "/api/auth/config" ? { required: false } : {} })
})
await page.goto("/ospf")
await page.getByRole("option").filter({ hasText: "Роутер 1" }).click()
const optimize = page.getByRole("button", { name: "Оптимизировать OSPF", exact: true })
await expect(optimize).toBeEnabled()
await expect(page.getByText("opt 10", { exact: true })).toHaveCount(0)
await optimize.evaluate(el => { (el as HTMLButtonElement).click(); (el as HTMLButtonElement).click() })
await expect.poll(() => writes).toBe(1)
await expect(page.getByRole("button", { name: "Оптимизация OSPF…", exact: true })).toBeDisabled()
await expect(page.getByRole("button", { name: "Обновить", exact: true })).toBeDisabled()
await page.getByRole("button", { name: "Обновить", exact: true }).evaluate(el => (el as HTMLButtonElement).click())
expect(reads).toBe(1)
release!()
await expect.poll(() => reads).toBe(2)
if (["http", "foreign", "malformed"].includes(outcome)) {
await expect(page.getByRole("alert").filter({ hasText: "Оптимизация OSPF не подтверждена" })).toBeVisible()
await expect(page.getByText("API подтвердил оптимизацию OSPF", { exact: false })).toHaveCount(0)
} else {
await expect(page.getByText("API подтвердил оптимизацию OSPF: 1 интерфейсов", { exact: true })).toBeVisible()
await expect(page.getByRole("group", { name: "Свежесть OSPF" }).locator('[data-ospf-time="write"]')).toContainText("API подтвердил оптимизацию устройства 1")
}
if (outcome === "poll-failure") {
await expect(page.getByRole("alert").filter({ hasText: "Опрос после записи недоступен" })).toBeVisible()
await expect(optimize).toBeDisabled()
} else await expect(optimize).toBeEnabled()
expect(writes).toBe(1)
})
}
test("OSPF: read-права не разрешают оптимизацию устройства", async ({ page }) => {
const payload = { sub: "test", email: "[email protected]", name: "Reader", apps: ["mm"], permissions: ["mm:network:read", "mm:servers:read"], exp: 4102444800 }
await page.addInitScript(value => localStorage.setItem("mmapp_token", "test." + btoa(JSON.stringify(value)) + ".test"), payload)
let writes = 0
await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
await page.route("**/api/**", r => {
const path = new URL(r.request().url()).pathname
if (r.request().method() === "POST") writes++
return r.fulfill({ json: path === "/api/auth/config" ? { required: true } : path === "/api/servers" ? [device] : path === "/api/ospf/catalog" ? catalog : {} })
})
await page.goto("/ospf")
await page.getByRole("option").filter({ hasText: "Роутер 1" }).click()
await expect(page.getByRole("button", { name: "Оптимизировать OSPF", exact: true })).toBeDisabled()
expect(writes).toBe(0)
})
for (const permission of ["mm:network:write", "mm:servers:write"]) {
test("OSPF: право оптимизации совпадает с backend — " + permission, async ({ page }) => {
await page.setViewportSize({ width: 320, height: 1000 })
const payload = { sub: "test", apps: ["mm"], permissions: ["mm:network:read", "mm:servers:read", permission], exp: 4102444800 }
await page.addInitScript(value => localStorage.setItem("mmapp_token", "test." + btoa(JSON.stringify(value)) + ".test"), payload)
let writes = 0
await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
await page.route("**/api/**", r => {
const path = new URL(r.request().url()).pathname
if (path === "/api/servers/1/ospf/optimize") { writes++; return r.fulfill({ json: result }) }
return r.fulfill({ json: path === "/api/auth/config" ? { required: true } : path === "/api/servers" ? [device] : path === "/api/ospf/catalog" ? catalog : {} })
})
await page.goto("/ospf?server=1&tab=interfaces")
const button = page.getByRole("button", { name: "Оптимизировать OSPF", exact: true })
if (permission === "mm:network:write") {
await expect(button).toBeEnabled(); await button.click()
await expect.poll(() => writes).toBe(1)
await expect(page.getByText("API подтвердил оптимизацию OSPF: 1 интерфейсов", { exact: true })).toBeVisible()
} else {
await expect(button).toBeDisabled()
await button.evaluate(el => (el as HTMLButtonElement).click())
expect(writes).toBe(0)
}
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true)
})
}