fix(alerts): проверять правила и группы до замены конфигурации
This commit is contained in:
1 parent
3556a378f2
commit
6093442bcf
10 files changed
+61
-10
No files matched your search
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"dev": "tsx watch src/index.ts",
|
||||
"build": "npm run build -w @mmapp/contracts && tsc",
|
||||
"test:alerts-telegram": "tsx src/services/alerts-telegram-settings.test.ts && tsx src/services/alerts-telegram-send.test.ts && tsx src/routes/alerts.test.ts && tsx src/plugins/auth.alerts.test.ts",
|
||||
"test:alerts-telegram": "tsx ../packages/contracts/src/alerts-normalization.test.ts && tsx src/services/alerts-telegram-settings.test.ts && tsx src/services/alerts-telegram-send.test.ts && tsx src/routes/alerts.test.ts && tsx src/plugins/auth.alerts.test.ts",
|
||||
"test:alert-engine": "tsx src/services/alert-engine/groups.test.ts && tsx src/services/alert-engine/evaluate-rule.test.ts && tsx src/services/alert-engine/confirm-stability.test.ts",
|
||||
"start": "node dist/index.js",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
|
||||
@@ -2,8 +2,9 @@ import assert from "node:assert/strict"
|
||||
import Fastify from "fastify"
|
||||
import {createAlertsRoutes,defaultAlertsDependencies} from "./alerts.js"
|
||||
import {executeTelegramSettingsUpdate} from "../services/alerts-telegram-settings.js"
|
||||
let replacements=0
|
||||
let stored={botToken:"fixture-secret",chatId:"123",messageThreadId:10 as number|null},reads=0,writes=0,sends=0,failSend=false,failWrite=false
|
||||
const app=Fastify();await app.register(createAlertsRoutes({...defaultAlertsDependencies,meta:async()=>({servers:[],greClients:[],probeTargets:[],rttLossTargets:[],trafficServers:[],serversDetail:[]}),telegram:async()=>({chatId:stored.chatId,tokenConfigured:!!stored.botToken,messageThreadId:stored.messageThreadId}),groups:async()=>[],rules:async()=>[],history:async()=>[],replace:async()=>{},writeTelegram:async patch=>executeTelegramSettingsUpdate(patch,{ensure:async()=>{},update:async values=>{writes++;if(failWrite)return undefined;stored={...stored,...values};return {...stored}}}),readTelegram:async()=>{reads++;return {...stored}},send:async input=>{sends++;assert.equal(input.token,"fixture-secret");assert.equal(input.chatId,"123");assert.equal(input.messageThreadId,10);return failSend?{ok:false,error:"send unknown"}:{ok:true}}}),{prefix:"/api"})
|
||||
const app=Fastify();await app.register(createAlertsRoutes({...defaultAlertsDependencies,meta:async()=>({servers:[],greClients:[],probeTargets:[],rttLossTargets:[],trafficServers:[],serversDetail:[]}),telegram:async()=>({chatId:stored.chatId,tokenConfigured:!!stored.botToken,messageThreadId:stored.messageThreadId}),groups:async()=>[],rules:async()=>[],history:async()=>[],replace:async()=>{replacements++},writeTelegram:async patch=>executeTelegramSettingsUpdate(patch,{ensure:async()=>{},update:async values=>{writes++;if(failWrite)return undefined;stored={...stored,...values};return {...stored}}}),readTelegram:async()=>{reads++;return {...stored}},send:async input=>{sends++;assert.equal(input.token,"fixture-secret");assert.equal(input.chatId,"123");assert.equal(input.messageThreadId,10);return failSend?{ok:false,error:"send unknown"}:{ok:true}}}),{prefix:"/api"})
|
||||
const test=()=>app.inject({method:"POST",url:"/api/alerts/telegram/test",payload:{}})
|
||||
let response=await app.inject({method:"GET",url:"/api/alerts"});assert.equal(response.statusCode,200);assert.equal(response.body.includes("fixture-secret"),false);assert.deepEqual(response.json().rules,[])
|
||||
response=await test();assert.equal(response.statusCode,200);assert.deepEqual(response.json(),{ok:true});assert.equal(reads,1);assert.equal(sends,1)
|
||||
@@ -13,4 +14,6 @@ for(const payload of [{},{token:4},{messageThreadId:1.5},{messageThreadId:214748
|
||||
response=await app.inject({method:"PUT",url:"/api/alerts/telegram",payload:{chatId:" new "}});assert.equal(response.statusCode,200);assert.equal(response.json().telegram.chatId,"new");assert.equal(stored.botToken,"fixture-secret");assert.equal(stored.messageThreadId,10);assert.equal(response.body.includes("fixture-secret"),false);assert.equal(writes,1)
|
||||
failWrite=true;response=await app.inject({method:"PUT",url:"/api/alerts/telegram",payload:{chatId:"other"}});assert.equal(response.statusCode,500);assert.equal(response.json().ok,undefined);assert.equal(writes,2)
|
||||
stored={...stored,botToken:""};response=await test();assert.equal(response.statusCode,400);assert.equal(sends,2)
|
||||
const invalidRule={id:"r",name:"Server",type:"server",target:"host",condition:"down",severity:"critical",enabled:false,cooldown:"5м",chatId:""}
|
||||
for(const payload of [{rules:[invalidRule,invalidRule],groups:[]},{rules:[{...invalidRule,targets:[" "]}],groups:[]},{rules:[{...invalidRule,groupId:"missing"}],groups:[]}]){response=await app.inject({method:"PUT",url:"/api/alerts/rules",payload});assert.equal(response.statusCode,400)}assert.equal(replacements,0)
|
||||
await app.close();console.log("Alerts HTTP: one stored test snapshot, strict numeric thread, selective save, unknown send/no retry, missing returning/no success, no token echo")
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from "../services/alerts-service.js"
|
||||
import {
|
||||
putRulesSchema,
|
||||
normalizeAlertsConfig,
|
||||
putTelegramSchema,
|
||||
testTelegramSchema,
|
||||
telegramSettingsReceiptSchema,
|
||||
@@ -41,6 +42,7 @@ export function createAlertsRoutes(deps:Dependencies):FastifyPluginAsyncZod {ret
|
||||
if (!parsed.success) {
|
||||
return reply.status(400).send({ error: "Некорректное тело запроса", details: parsed.error.flatten() })
|
||||
}
|
||||
try { normalizeAlertsConfig(parsed.data) } catch { return reply.status(400).send({error:"Проверьте объекты, условия и группы правил"}) }
|
||||
const groups =
|
||||
parsed.data.groups ??
|
||||
(await deps.groups()).map((g) => ({
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import {normalizeAlertsConfig} from "@mmapp/contracts/alerts"
|
||||
import {sendTelegramRequest} from "./alerts-telegram-send.js"
|
||||
import {executeTelegramSettingsUpdate} from "./alerts-telegram-settings.js"
|
||||
import { asc, desc, eq, sql } from "drizzle-orm"
|
||||
@@ -206,7 +207,9 @@ export type ReplaceAlertGroupInput = {
|
||||
/** Атомарно заменяет группы, правила и строки targets. */
|
||||
export async function replaceAlertsConfig(payload: { groups: ReplaceAlertGroupInput[]; rules: ReplaceAlertRuleInput[] }) {
|
||||
const now = sql`now()`
|
||||
const { groups, rules } = payload
|
||||
const normalized = normalizeAlertsConfig(payload)
|
||||
const groups = normalized.groups!
|
||||
const rules = normalized.rules
|
||||
await db.transaction(async (tx) => {
|
||||
await tx.delete(alertRuleConditions)
|
||||
await tx.delete(alertRuleTargets)
|
||||
|
||||
Reference in new issue
Block a user