fix(alerts): проверять каталоги объектов и сохранять частичные сбои
This commit is contained in:
1 parent
3710fc6aab
commit
a8a3eb59fb
5 files changed
+38
-2
No files matched your search
@@ -0,0 +1,8 @@
|
||||
import assert from "node:assert/strict"
|
||||
import {test} from "node:test"
|
||||
import {getAlertsBgpTargets,getAlertsServerTargets,getAlertsGreTargets} from "./alerts-targets"
|
||||
test("Alerts target readers preserve known empty collections and unknown optional GRE status",async()=>{const original=globalThis.fetch;try{globalThis.fetch=async()=>Response.json([]);assert.deepEqual(await getAlertsBgpTargets("https://backend.test"),[]);assert.deepEqual(await getAlertsServerTargets("https://backend.test"),[]);globalThis.fetch=async()=>Response.json({tunnels:[]});assert.deepEqual(await getAlertsGreTargets("https://backend.test"),{tunnels:[]});globalThis.fetch=async()=>Response.json({tunnels:[{name:"gre1",serverId:"1"}]});assert.equal((await getAlertsGreTargets("https://backend.test")).tunnels[0].status,undefined)}finally{globalThis.fetch=original}})
|
||||
test("Alerts malformed secondary catalogs reject instead of fabricating empty/down",async()=>{const original=globalThis.fetch;try{for(const [call,raw] of [[getAlertsBgpTargets,{}],[getAlertsBgpTargets,[{serverName:"",name:"peer"}]],[getAlertsServerTargets,[{id:"1",name:"server"}]],[getAlertsServerTargets,[{id:1.5,name:"server"}]],[getAlertsGreTargets,{}],[getAlertsGreTargets,{tunnels:null}],[getAlertsGreTargets,{tunnels:[{name:"gre",serverId:""}]}]] as const){globalThis.fetch=async()=>Response.json(raw);await assert.rejects(call("https://backend.test"),/не подтверждён/)}}finally{globalThis.fetch=original}})
|
||||
test("Alerts target readers reject pre-abort before GET and use independent bounded signals",async()=>{const original=globalThis.fetch;let calls=0;try{globalThis.fetch=async()=>{calls++;return Response.json([])};const controller=new AbortController();controller.abort();for(const call of [getAlertsBgpTargets,getAlertsServerTargets,getAlertsGreTargets])await assert.rejects(call("https://backend.test",{signal:controller.signal}));assert.equal(calls,0);globalThis.fetch=async(_url,init)=>{assert.ok(init?.signal);return Response.json([])};await getAlertsBgpTargets("https://backend.test")}finally{globalThis.fetch=original}})
|
||||
|
||||
test("Alerts GRE reader preserves partial device failures instead of treating missing tunnels as complete",async()=>{const original=globalThis.fetch;try{const failures=[{serverId:"1",serverName:"Router",error:"unavailable"}];globalThis.fetch=async()=>Response.json({tunnels:[],failures});assert.deepEqual((await getAlertsGreTargets("https://backend.test")).failures,failures)}finally{globalThis.fetch=original}})
|
||||
@@ -0,0 +1,17 @@
|
||||
import {z} from "zod"
|
||||
import {requestJson} from "./http-client"
|
||||
const bgpSchema=z.array(z.object({serverName:z.string().trim().min(1),name:z.string().trim().min(1)}))
|
||||
const serversSchema=z.array(z.object({id:z.number().int().positive(),name:z.string(),site:z.string().optional(),country:z.string().optional(),host:z.string().optional()}))
|
||||
const greSchema=z.object({tunnels:z.array(z.object({id:z.string().optional(),name:z.string(),serverId:z.string().min(1),remoteAddress:z.string().optional(),status:z.string().optional(),comment:z.string().optional()})),failures:z.array(z.object({serverId:z.string().min(1),serverName:z.string(),error:z.string()})).optional()})
|
||||
type Options={signal?:AbortSignal}
|
||||
async function read<S extends z.ZodType>(base:string,path:string,schema:S,message:string,options?:Options):Promise<z.output<S>>{
|
||||
const signal=options?.signal?AbortSignal.any([options.signal,AbortSignal.timeout(30_000)]):AbortSignal.timeout(30_000)
|
||||
signal.throwIfAborted()
|
||||
const parsed=schema.safeParse(await requestJson<unknown>(base,path,{signal,cache:"no-store"}))
|
||||
signal.throwIfAborted()
|
||||
if(!parsed.success)throw Error(message)
|
||||
return parsed.data
|
||||
}
|
||||
export const getAlertsBgpTargets=(base:string,options?:Options)=>read(base,"/api/bgp/sessions",bgpSchema,"Каталог BGP для оповещений не подтверждён",options)
|
||||
export const getAlertsServerTargets=(base:string,options?:Options)=>read(base,"/api/servers",serversSchema,"Каталог серверов для оповещений не подтверждён",options)
|
||||
export const getAlertsGreTargets=(base:string,options?:Options)=>read(base,"/api/filters/gre-tunnels",greSchema,"Каталог GRE для оповещений не подтверждён",options)
|
||||
Reference in new issue
Block a user