fix(alerts): разделить загрузку каталогов целей и правил
This commit is contained in:
1 parent
a8a3eb59fb
commit
526f305aa6
11 files changed
+153
-77
No files matched your search
@@ -0,0 +1,13 @@
|
||||
import {test,expect,type Page} from "@playwright/test"
|
||||
import {emptyAlerts} from "./fixtures/alerts"
|
||||
const headers={"access-control-allow-origin":"*","access-control-allow-methods":"GET,OPTIONS","access-control-allow-headers":"Content-Type,Authorization"}
|
||||
async function source(page:Page,value:string){const input=page.getByRole("textbox",{name:"URL бекенда",exact:true});await input.fill(value);await input.press("Enter");await expect(input).toHaveValue(value);await expect(page.getByText("Доступен",{exact:true})).toBeVisible()}
|
||||
for(const failed of [false,true])test("Alerts source: ABA discards old primary and target outcomes/"+failed,async({page})=>{
|
||||
const startedPaths=new Set<string>();let old=true,started=0,completed=0,release!:()=>void;const gate=new Promise<void>(resolve=>release=resolve)
|
||||
await page.route("**/health",r=>r.fulfill({headers,json:{status:"ok"}}))
|
||||
await page.route("**/api/**",async r=>{const url=new URL(r.request().url()),path=url.pathname;if(path==="/api/auth/config")return r.fulfill({headers,json:{required:false}})
|
||||
if(old&&url.port==="8000"&&["/api/alerts","/api/bgp/sessions","/api/filters/gre-tunnels"].includes(path)){started++;startedPaths.add(path);await gate;try{await r.fulfill(failed?{headers,status:503,json:{error:"OLD ALERTS FAILED"}}:{headers,json:path==="/api/alerts"?{...emptyAlerts,telegram:{...emptyAlerts.telegram,chatId:"OLD CHAT"}}:path==="/api/bgp/sessions"?[{serverName:"old",name:"peer"}]:{tunnels:[{name:"old",serverId:"1"}]}})}catch{}finally{completed++};return}
|
||||
return r.fulfill({headers,json:path==="/api/alerts"?emptyAlerts:path==="/api/filters/gre-tunnels"?{tunnels:[],failures:[]}:[]})})
|
||||
try{await page.goto("/alerts");await expect.poll(()=>startedPaths.size).toBe(3);await page.goto("/settings");await source(page,"http://localhost:8101");old=false;await source(page,"http://localhost:8000");await page.goto("/alerts");await expect(page.getByText("Всего: 0",{exact:true})).toBeVisible();release();await expect.poll(()=>completed).toBe(started);await expect(page.getByText("OLD ALERTS FAILED",{exact:true})).toHaveCount(0);await expect(page.locator('input[value="OLD CHAT"]')).toHaveCount(0);for(const label of ["BGP","GRE"])await expect(page.getByRole("region",{name:"Каталог "+label,exact:true})).toContainText("Получено объектов: 0")
|
||||
}finally{release()}
|
||||
})
|
||||
@@ -0,0 +1,30 @@
|
||||
import {test,expect,type Page,type Route} from "@playwright/test"
|
||||
import {emptyAlerts} from "./fixtures/alerts"
|
||||
async function setup(page:Page,secondary:(route:Route,path:string)=>Promise<unknown>,required=false){
|
||||
await page.route("**/health",r=>r.fulfill({json:{status:"ok"}}))
|
||||
await page.route("**/api/**",r=>{const path=new URL(r.request().url()).pathname;if(path==="/api/auth/config")return r.fulfill({json:{required}});if(path==="/api/alerts")return r.fulfill({json:emptyAlerts});return secondary(r,path)})
|
||||
await page.goto("/alerts")
|
||||
}
|
||||
test("Alerts catalogs: delayed BGP does not block primary or GRE",async({page})=>{
|
||||
let started=false,release!:()=>void;const gate=new Promise<void>(resolve=>release=resolve)
|
||||
try{await setup(page,async(r,path)=>{if(path==="/api/bgp/sessions"){started=true;await gate;try{await r.fulfill({json:[]})}catch{};return}return r.fulfill({json:path==="/api/servers"?[]:{tunnels:[],failures:[]}})})
|
||||
await expect.poll(()=>started).toBe(true);await expect(page.getByText("Всего: 0",{exact:true})).toBeVisible();await expect(page.getByRole("button",{name:"Обновить",exact:true})).toBeEnabled();await expect(page.getByRole("region",{name:"Каталог GRE",exact:true})).toContainText("Получено объектов: 0");await expect(page.getByRole("region",{name:"Каталог BGP",exact:true})).toContainText("Обновление…");release();await expect(page.getByRole("region",{name:"Каталог BGP",exact:true})).toContainText("Получено объектов: 0")
|
||||
}finally{release()}
|
||||
})
|
||||
test("Alerts catalogs: partial GRE and malformed refresh preserve last complete snapshot",async({page})=>{
|
||||
let response:unknown={tunnels:[{name:"gre-fixture",serverId:"1"}],failures:[]};let greCalls=0,bgpCalls=0
|
||||
await setup(page,(r,path)=>{if(path==="/api/filters/gre-tunnels"){greCalls++;return r.fulfill({json:response})}if(path==="/api/bgp/sessions"){bgpCalls++;return r.fulfill({json:[]})}return r.fulfill({json:[]})})
|
||||
const gre=page.getByRole("region",{name:"Каталог GRE",exact:true});await expect(gre).toContainText("Получено объектов: 1");const time=await gre.getByRole("status").innerText();const previousBgpCalls=bgpCalls,previousGreCalls=greCalls
|
||||
response={tunnels:[],failures:[{serverId:"2",serverName:"router-fixture",error:"offline"}]};await gre.getByRole("button").click();await expect(gre.getByRole("alert")).toContainText("Неполный каталог GRE");await expect(gre.getByRole("status")).toHaveText(time);expect(bgpCalls).toBe(previousBgpCalls)
|
||||
response={tunnels:null};await gre.getByRole("button").click();await expect(gre.getByRole("alert")).toContainText("Каталог GRE для оповещений не подтверждён");await expect(gre.getByRole("status")).toHaveText(time);expect(greCalls).toBe(previousGreCalls+2)
|
||||
})
|
||||
test("Alerts catalogs: initial partial GRE remains unknown",async({page})=>{await setup(page,(r,path)=>r.fulfill({json:path==="/api/filters/gre-tunnels"?{tunnels:[],failures:[{serverId:"1",serverName:"router-fixture",error:"offline"}]}:[]}));const gre=page.getByRole("region",{name:"Каталог GRE",exact:true});await expect(gre.getByRole("alert")).toContainText("Неполный каталог GRE");await expect(gre.getByRole("status")).toHaveText("Данные ещё не получены.");await expect(gre).not.toContainText("Получено объектов: 0")})
|
||||
|
||||
test("Alerts catalogs: alerts read permission does not grant network catalog access",async({page})=>{
|
||||
const token="header."+Buffer.from(JSON.stringify({sub:"fixture",apps:["mm"],permissions:["mm:alerts:read"],exp:Math.floor(Date.now()/1000)+3600})).toString("base64url")+".fixture"
|
||||
await page.addInitScript(value=>localStorage.setItem("mmapp_token",value),token)
|
||||
let calls=0;await setup(page,(r,path)=>{if(["/api/bgp/sessions","/api/filters/gre-tunnels"].includes(path))calls++;return r.fulfill({json:[]})},true)
|
||||
await expect(page.getByText("Всего: 0",{exact:true})).toBeVisible()
|
||||
for(const label of ["BGP","Серверы","GRE"])await expect(page.getByRole("region",{name:"Каталог "+label,exact:true}).getByRole("alert")).toHaveText("Нет доступа к каталогу")
|
||||
expect(calls).toBe(0)
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
export const emptyAlerts={telegram:{chatId:"",tokenConfigured:false,connected:false,messageThreadId:null},groups:[],rules:[],history:[],meta:{servers:[],greClients:[],probeTargets:[],rttLossTargets:[],trafficServers:[],serversDetail:[]}}
|
||||
Reference in new issue
Block a user