mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 08:09:27 +00:00
## Summary
- Adds `alerts-metrics-notification.spec.js` — a 3-test UI suite
verifying the full metrics alert chain
- Test 1 (P1): PromQL alert triggers via scheduler, verified in history
UI — self-contained using `ensureMetricsIngested()`
- Test 2 (P2): Template body contains required alert variables
(`{alert_url}`, `{alert_name}`, `{stream_name}`)
- Test 3 (P1): Manual trigger from alert list more-options menu sends
notification
- Includes `alert-metrics-notification-findings.md` documenting manual
testing results (API schema, PromQL vs SQL, trigger indicators)
## Test plan
- [ ] Test 1: Alert triggers on freshly ingested `cpu_usage` metrics and
history rows appear in UI
- [ ] Test 2: Template editor (Monaco) shows expected variables
- [ ] Test 3: Manual trigger menu option calls PATCH /trigger and
succeeds
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
99 lines
2.9 KiB
JavaScript
99 lines
2.9 KiB
JavaScript
/**
|
|
* Webhook capture server — lightweight HTTP receiver for E2E tests.
|
|
*
|
|
* Spins up a local HTTP server that captures incoming POST bodies so tests
|
|
* can assert on outbound alert notification payloads (template rendering,
|
|
* variable substitution, alert_url correctness) without depending on
|
|
* external services like httpbin.org.
|
|
*
|
|
* Only works when the backend can reach localhost (e.g., CI or local dev).
|
|
*/
|
|
const http = require('http');
|
|
|
|
class WebhookCapture {
|
|
constructor() {
|
|
this.server = null;
|
|
this.port = 0;
|
|
this.payloads = [];
|
|
}
|
|
|
|
/**
|
|
* Start the capture server on a free port.
|
|
* @returns {Promise<number>} The port the server is listening on.
|
|
*/
|
|
async start() {
|
|
return new Promise((resolve, reject) => {
|
|
this.payloads = [];
|
|
this.server = http.createServer((req, res) => {
|
|
let body = '';
|
|
req.on('data', chunk => { body += chunk; });
|
|
req.on('end', () => {
|
|
try {
|
|
this.payloads.push({
|
|
method: req.method,
|
|
url: req.url,
|
|
headers: req.headers,
|
|
body: JSON.parse(body || '{}'),
|
|
rawBody: body,
|
|
timestamp: Date.now(),
|
|
});
|
|
} catch {
|
|
this.payloads.push({
|
|
method: req.method,
|
|
url: req.url,
|
|
headers: req.headers,
|
|
rawBody: body,
|
|
timestamp: Date.now(),
|
|
});
|
|
}
|
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify({ received: true }));
|
|
});
|
|
});
|
|
|
|
this.server.on('error', reject);
|
|
this.server.listen(0, '127.0.0.1', () => {
|
|
this.port = this.server.address().port;
|
|
resolve(this.port);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Stop the capture server.
|
|
*/
|
|
async stop() {
|
|
return new Promise((resolve) => {
|
|
if (!this.server) return resolve();
|
|
this.server.close(() => resolve());
|
|
this.server = null;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get all captured payloads.
|
|
* @returns {Array} Array of captured request objects.
|
|
*/
|
|
getPayloads() {
|
|
return this.payloads;
|
|
}
|
|
|
|
/**
|
|
* Get the most recent captured payload body.
|
|
* @returns {Object|null}
|
|
*/
|
|
getLatestPayload() {
|
|
if (this.payloads.length === 0) return null;
|
|
return this.payloads[this.payloads.length - 1];
|
|
}
|
|
|
|
/**
|
|
* Clear all captured payloads (useful between test phases).
|
|
*/
|
|
clear() {
|
|
this.payloads = [];
|
|
}
|
|
}
|
|
|
|
module.exports = { WebhookCapture };
|