Problem
OpenAlerts currently has zero test coverage. The core engine, all 8 alert rules, the evaluator, the JSONL store, the event bus, the formatter, and the bounded map are all untested. This makes it risky to accept contributions or refactor internals there's no safety net to catch regressions.
The publish CI workflow also has no test step, so broken code can ship to npm undetected.
Proposal
Add a comprehensive test suite using Vitest (fast, TypeScript-native, zero-config for ESM projects). The suite should cover the framework-agnostic src/core/ layer the part that every adapter depends on.
Proposed test files
| File |
Covers |
tests/rules.test.ts |
All 8 alert rules in isolation |
tests/evaluator.test.ts |
processEvent(), warmFromHistory(), stats tracking, hourly cap |
tests/store.test.ts |
JSONL append, read, prune (age + size), atomic write |
tests/engine.test.ts |
OpenAlertsEngine lifecycle — start, stop, ingest → alert flow |
tests/formatter.test.ts |
/health and /alerts output formatting |
tests/bounded-map.test.ts |
LRU eviction, TTL expiry, hit/miss stats |
tests/event-bus.test.ts |
Pub/sub, listener error isolation |
Key test cases for rules (rules.test.ts)
llm-errors
- Fires after ≥1 error-outcome
llm.call event in a 1-minute window
- Does NOT fire for
llm.call with outcome: "success" or undefined
- Fires for
llm.error and agent.error event types (always treated as errors)
- Respects configurable
threshold override
gateway-down
- Only evaluates on
watchdog.tick events (ignores all other types)
- Returns
null when no heartbeat has ever been received (lastHeartbeatTs === 0)
- Fires when silence exceeds threshold (default 30s)
- Severity is
critical
high-error-rate
- Does NOT fire until at least 20 messages have been tracked
- Calculates rate over the last 20 messages only (sliding window)
- Fires at ≥50% error rate by default
- Counts
timeout outcomes as errors
queue-depth
- Updates
lastHeartbeatTs on infra.heartbeat events regardless of whether the rule itself is enabled (gateway-down depends on this)
- Fires when
queueDepth ≥ threshold
Cross-cutting (evaluator)
- Cooldown prevents the same fingerprint from firing twice within the cooldown window
- Hourly cap (default 5) blocks the 6th alert in the same hour
- Hourly cap resets after the hour expires
- Cooldown map is pruned when it exceeds
maxCooldownEntries (50)
- 24h stats reset after 24 hours
warmFromHistory() restores cooldowns from persisted alert events
warmFromHistory() does NOT replay diagnostic events through rules
Setup
Add to package.json:
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest"
}
}
Add to tsconfig.json (or a tsconfig.test.json):
I'd like to work on this , happy to submit a PR if this fits in. Thanks!
Problem
OpenAlerts currently has zero test coverage. The core engine, all 8 alert rules, the evaluator, the JSONL store, the event bus, the formatter, and the bounded map are all untested. This makes it risky to accept contributions or refactor internals there's no safety net to catch regressions.
The publish CI workflow also has no test step, so broken code can ship to npm undetected.
Proposal
Add a comprehensive test suite using Vitest (fast, TypeScript-native, zero-config for ESM projects). The suite should cover the framework-agnostic
src/core/layer the part that every adapter depends on.Proposed test files
tests/rules.test.tstests/evaluator.test.tsprocessEvent(),warmFromHistory(), stats tracking, hourly captests/store.test.tstests/engine.test.tsOpenAlertsEnginelifecycle — start, stop, ingest → alert flowtests/formatter.test.ts/healthand/alertsoutput formattingtests/bounded-map.test.tstests/event-bus.test.tsKey test cases for rules (
rules.test.ts)llm-errorsllm.callevent in a 1-minute windowllm.callwithoutcome: "success"orundefinedllm.errorandagent.errorevent types (always treated as errors)thresholdoverridegateway-downwatchdog.tickevents (ignores all other types)nullwhen no heartbeat has ever been received (lastHeartbeatTs === 0)criticalhigh-error-ratetimeoutoutcomes as errorsqueue-depthlastHeartbeatTsoninfra.heartbeatevents regardless of whether the rule itself is enabled (gateway-down depends on this)queueDepth≥ thresholdCross-cutting (evaluator)
maxCooldownEntries(50)warmFromHistory()restores cooldowns from persisted alert eventswarmFromHistory()does NOT replay diagnostic events through rulesSetup
Add to
package.json:{ "scripts": { "test": "vitest run", "test:watch": "vitest" } }Add to
tsconfig.json(or atsconfig.test.json):{ "exclude": ["tests"] // don't emit test files to dist/ }I'd like to work on this , happy to submit a PR if this fits in. Thanks!