- LIKE wildcard injection: sanitize %, _ in search queries (devices, sites, gaiia) - Jason.decode! → Jason.decode with error handling for untrusted input - inspect() leak: replace with generic error messages, log details server-side - SSRF protection: URL validator blocks private IPs, localhost, non-HTTP schemes - SSRF validation added to HTTP monitoring executor and integration credentials - GraphQL complexity limits: always applied, not just in prod - GraphQL introspection: also check GET query params, not just body - Stripe webhook: explicit nil/empty checks for signature and body - Cookie security: secure flag for session (prod), http_only+secure for remember_me - Honeybadger API key: read from env var with fallback - String.to_integer → Integer.parse with fallback for URL params - String.to_atom → whitelist map for HTTP methods - Gaiia webhook: remove secret_len and expected signature from log - Admin API: add rate limiting pipeline - to_atom_keys: per-key fallback instead of all-or-nothing rescue
12 KiB
TowerOps Test Coverage Report
Generated: 2026-03-13 Test Run: 90 doctests, 55 properties, 8,134 tests | 4 failures, 38 skipped, 231 excluded Duration: 158.2s (40.5s async, 117.6s sync)
Summary
| Metric | Count |
|---|---|
| Total test files | 547 |
| Total tests (incl. doctests/properties) | 8,279 |
| Passing | 8,237 |
| Failures | 4 |
| Skipped | 38 |
| Excluded | 231 |
| Source modules (excl. vendor profiles, migrations, proto) | ~230 |
| Web modules (controllers, LiveViews, plugs, etc.) | ~140 |
| Modules with NO test file | ~100 |
Current Failures (4)
ToweropsWeb.AgentLive.IndexTest— Unique constraint violation onagents.slugduring setup (test data collision)ToweropsWeb.AgentLive.IndexTest— Same slug collision in cloud poller creation setupToweropsWeb.AgentLive.IndexTest— Same root cause, different describe blockToweropsWeb.GraphQL.Resolvers.TimeSeriesTest— Deadlock oncreate_check_result(async test hittingShareRowExclusiveLock)
Both are infrastructure/setup issues, not logic bugs. The agent slug collision likely needs a unique factory counter; the deadlock needs
async: falseor transaction isolation.
Test Infrastructure & Patterns
Case Templates
ToweropsWeb.ConnCase— HTTP/LiveView tests. ImportsPhoenix.ConnTest,Plug.Conn, verified routes. Hasregister_and_log_in_user/1and sudo variant.Towerops.DataCase— Context/schema tests. ImportsEcto,Ecto.Changeset,Ecto.Query,Towerops.Repo. SQL Sandbox isolation.ToweropsWeb.LiveViewTestHelpers— Shared helpers for LiveView tests.
Fixtures (Factory Pattern)
All in test/support/fixtures/:
accounts_fixtures.ex— Users, tokens, TOTPagents_fixtures.ex— Agents, assignments, tokensbilling_fixtures.ex— Stripe datadevices_fixtures.ex— Devices, firmwaregaiia_fixtures.ex— GAIIA accounts, subscribersintegrations_fixtures.ex— Integration configsjobs_fixtures.ex— Oban jobsmaintenance_fixtures.ex— Maintenance windowson_call_fixtures.ex— Schedules, escalation policiesorganizations_fixtures.ex— Orgs, memberships, invitationssnmp_fixtures.ex— SNMP devices, interfaces
Test Types
- Async tests: ~442 files use
async: true - Property tests: 55 (using
StreamData) - Doctests: 90
- Integration tests:
test/integration/(SNMP, discovery parity) - SnmpKit tests: Dedicated
test/snmpkit/directory with ~45 test files
Mocking
Mox— Used for behaviour-based mocks (SNMP, ping, HTTP)ping_stub.ex— Stub for ping behavioursnmp_kit_mock.ex— SNMP client mock
Coverage by Domain
✅ Well-Covered Domains
| Domain | Source Files | Test Files | Notes |
|---|---|---|---|
| Accounts | 13 | 14+ | Comprehensive auth, TOTP, sessions, HIBP, browser sessions |
| Agents | 5 | 8+ | Assignments, tokens, stats, release checker, cloud poller |
| Alerts | 2 | 2 | Alert schema + context |
| API Tokens | 2 | 2 | Token CRUD |
| Billing | 5 | 4 | Stripe client, webhook processor, notifier (missing: stripe_webhook_event schema) |
| Devices | 14 | 10+ | Core CRUD, firmware, backups, differ, version comparator |
| GAIIA | 14 | 13 | Excellent: sync, reconciliation, subscriber matching, impact analysis |
| Organizations | 6 | 7+ | Policies, invitations, subscriptions, property tests |
| Preseem | 14 | 14 | Full coverage: sync, baselines, insights, fleet intelligence |
| Profiles | 7 | 5 | YAML profiles, device/sensor OIDs |
| SNMP Core | 30+ | 25+ | Discovery, polling, sanitizer, sensor change, MIB parsing |
| SNMP Vendors | 180+ | 180+ | Auto-generated, 1:1 coverage |
| Workers | 30 | 22 | Most critical workers covered |
| Web: Plugs | 13 | 11 | Auth, rate limiting, security headers, brute force |
| Web: Controllers | 25+ | 25+ | API v1, admin, auth flow controllers |
| Web: LiveViews | 40+ | 35+ | Most major pages tested |
⚠️ Gaps — Modules Without Test Files
🔴 Critical (Needs Tests NOW)
These modules handle auth, billing, alert routing, or data mutations with no dedicated tests:
| Module | Why Critical |
|---|---|
Towerops.Monitoring (context) |
Core monitoring orchestration — check creation, status evaluation |
Towerops.Monitoring.Executor |
Dispatches monitoring checks to executors |
Towerops.Monitoring.Executors.DnsExecutor |
DNS monitoring — untested execution path |
Towerops.Monitoring.Executors.HttpExecutor |
HTTP monitoring — untested execution path |
Towerops.Monitoring.Executors.TcpExecutor |
TCP monitoring — untested execution path |
Towerops.Monitoring.Executors.SnmpInterfaceExecutor |
SNMP interface monitoring |
Towerops.Monitoring.Executors.SnmpProcessorExecutor |
SNMP CPU monitoring |
Towerops.Monitoring.Executors.SnmpStorageExecutor |
SNMP storage monitoring |
Towerops.OnCall.Notifier |
Sends on-call notifications — critical alert path |
Towerops.OnCall.Incident |
Incident lifecycle — create, ack, resolve |
Towerops.OnCall.EscalationPolicy |
Escalation rule evaluation |
Towerops.OnCall.Notification |
Notification delivery schema |
Towerops.PagerDuty.Notifier |
External PagerDuty alert dispatch |
Towerops.Security.CloudflareClient |
Cloudflare IP banning — security mutation |
Towerops.Security.IpBlock / IpWhitelist |
IP access control schemas |
Towerops.Billing.StripeWebhookEvent |
Stripe event persistence schema |
Towerops.Accounts.UserRecoveryCode |
Account recovery — security-critical |
Towerops.Accounts.UserToken |
Token schema (tested indirectly via Accounts context but no direct schema test) |
🟠 High Priority
| Module | Why |
|---|---|
Towerops.Maintenance (context) |
Maintenance window CRUD and scheduling logic |
Towerops.ConfigChanges (context) |
Config change tracking and correlation |
Towerops.ConfigChanges.Correlator |
Correlates config changes to alerts |
Towerops.Topology.Lldp |
LLDP neighbor discovery logic |
Towerops.Topology.Identifier |
Device identification heuristics |
Towerops.Netbox.Sync |
External NetBox sync — data import |
Towerops.Sonar.Client / Sync |
Sonar billing integration |
Towerops.Weather.Client |
Weather API integration |
Towerops.Workers.EscalationCheckWorker |
Periodic escalation evaluation |
Towerops.Workers.CheckWorker |
Monitoring check scheduling |
Towerops.Workers.MikrotikBackupWorker |
MikroTik backup orchestration |
Towerops.Workers.CloudflareBanWorker |
Security: auto-ban via Cloudflare |
ToweropsWeb.Controllers.Api.V1.PagerdutyWebhookController |
Inbound PagerDuty webhooks |
ToweropsWeb.Controllers.Api.V1.ActivityController |
Activity feed API |
ToweropsWeb.Controllers.Api.V1.CheckResultsController |
Check results API |
ToweropsWeb.Controllers.InvitationController |
Org invitation acceptance |
ToweropsWeb.Controllers.UserConfirmationController |
Email confirmation flow |
ToweropsWeb.Controllers.UserRegistrationController |
User signup flow |
ToweropsWeb.Live.OnboardingLive |
New user onboarding |
ToweropsWeb.Live.Org.GaiiaMappingLive |
GAIIA device mapping UI |
ToweropsWeb.Live.Org.GaiiaReconciliationLive |
GAIIA reconciliation UI |
🟡 Medium Priority
| Module | Why |
|---|---|
Towerops.Geocoding |
Address-to-coordinates (read-only helper) |
Towerops.GeoIp.Block / Location |
GeoIP lookup schemas |
Towerops.Vault |
Encryption key management |
Towerops.RateLimit |
Rate limiting logic |
Towerops.Devices.Event / BackupRequest |
Event/request schemas |
Towerops.Devices.MikrotikBackup |
Backup schema |
Towerops.OnCall.Schedule / Layer / Override |
On-call schedule schemas |
Towerops.Organizations.Membership |
Membership schema |
Towerops.SNMP.Interface / Sensor / Device schemas |
Data schemas |
Towerops.Workers.*SyncWorker (sonar, splynx, visp, weather, netbox) |
Sync orchestration |
ToweropsWeb.Live.CapacityLive |
Capacity planning page |
ToweropsWeb.Live.ConfigTimelineLive |
Config change timeline |
ToweropsWeb.Live.ActivityFeedLive |
Activity feed page |
ToweropsWeb.Live.MikrotikBackupLive.Compare |
Backup diff viewer |
ToweropsWeb.GraphQL.Context |
GraphQL context setup |
🟢 Low Priority
| Module | Notes |
|---|---|
Towerops.EctoTypes.EncryptedBinary |
Simple Ecto type (encrypted_map is tested) |
Towerops.Settings.ApplicationSetting |
Simple schema |
Towerops.Mailer |
Swoosh wrapper |
Towerops.Release |
Mix release tasks |
Towerops.Repo |
Ecto repo module |
Towerops.SNMP.SnmpBehaviour |
Behaviour definition |
Towerops.SNMP.PollerBehaviour |
Behaviour definition |
Towerops.Monitoring.PingBehaviour |
Behaviour definition |
Towerops.Profiles.MibCache / ProfileWatcher |
GenServer infrastructure |
| Various SNMP data schemas (readings, stats) | Simple structs |
Top 10 Recommended Tests to Write
1. test/towerops/monitoring_test.exs — Monitoring Context
Impact: 🔴 Critical
Cover: create_check/2, update_check/2, delete_check/2, list_checks_for_device/1, check result creation and status evaluation. This is the core monitoring orchestration layer with zero test coverage.
2. test/towerops/monitoring/executor_test.exs — Check Executor Dispatch
Impact: 🔴 Critical Cover: Executor dispatch logic, timeout handling, error wrapping. Test with mocked executors that the right executor is called for each check type (HTTP, DNS, TCP, SNMP).
3. test/towerops/on_call/notifier_test.exs — On-Call Notification Delivery
Impact: 🔴 Critical Cover: Notification channel selection (email, SMS, push), retry logic, escalation triggering, de-duplication. Mock external delivery and verify correct notification flow.
4. test/towerops/on_call/incident_test.exs — Incident Lifecycle
Impact: 🔴 Critical Cover: Incident creation from alert, acknowledgment, resolution, re-escalation on timeout. Verify state machine transitions and escalation policy evaluation.
5. test/towerops/monitoring/executors/http_executor_test.exs — HTTP Check Execution
Impact: 🔴 Critical Cover: HTTP status checks, response time measurement, SSL verification, timeout handling, redirect following, body content matching. Mock HTTP client.
6. test/towerops/config_changes_test.exs — Config Change Tracking
Impact: 🟠 High Cover: Change event creation, correlation with alerts/devices, timeline querying, diff computation. Verify correlator links config changes to relevant alerts.
7. test/towerops/maintenance_test.exs — Maintenance Window Context
Impact: 🟠 High
Cover: Window creation/scheduling, overlap detection, active window queries, alert suppression during maintenance. Verify is_in_maintenance?/2 logic.
8. test/towerops_web/controllers/api/v1/pagerduty_webhook_controller_test.exs — PagerDuty Webhooks
Impact: 🟠 High Cover: Webhook signature verification, event type handling (trigger, acknowledge, resolve), idempotency, error responses for invalid payloads.
9. test/towerops/security/cloudflare_client_test.exs — Cloudflare IP Management
Impact: 🟠 High Cover: IP block creation/deletion via Cloudflare API, error handling, rate limiting. Mock Cloudflare API. Verify the ban worker integrates correctly.
10. test/towerops_web/controllers/user_registration_controller_test.exs — User Registration
Impact: 🟠 High Cover: Successful registration, duplicate email handling, password validation, email confirmation trigger, registration with invitation token. Critical auth flow.
Test Health Notes
- Async ratio is excellent — ~81% of test files use
async: true - Property testing is in use — 55 property tests via StreamData (found in schema validation, Ecto type tests)
- Fixture coverage is comprehensive — 14 fixture modules covering all major domains
- Vendor profile tests are auto-generated — 180+ vendor tests likely from
mix gen_vendor_tests - The 4 current failures are infrastructure issues, not logic bugs:
- Agent slug uniqueness collision in test factories → fix: add
System.unique_integer()to slug generation - Deadlock in async time series test → fix: set
async: falseor restructure DB access
- Agent slug uniqueness collision in test factories → fix: add
- 231 excluded tests — likely tagged
:integrationor:externalfor CI isolation - 38 skipped tests — worth auditing to see if any are permanently broken