Commit graph

940 commits

Author SHA1 Message Date
rcourtman
7ab68cf682 Fix offline buffering: add tests, remove unused config, fix flaky test
- Add unit tests for internal/buffer package
- Fix misleading "ring buffer" comment (it's a bounded FIFO queue)
- Remove unused BufferCapacity config field from both agents
- Rewrite flaky integration test to use polling instead of fixed sleeps
2025-12-02 22:31:44 +00:00
courtmanr@gmail.com
b2d434b4c2 feat: Implement offline buffering for host and docker agents
- Add internal/buffer package with generic ring buffer
- Add buffering logic to host agent for failed reports
- Add buffering logic to docker agent for failed reports
- Add BufferCapacity configuration option
- Add integration tests for buffering logic
2025-12-02 22:12:47 +00:00
rcourtman
93223d8283 Add refresh-cluster button to detect new Proxmox cluster members
When new nodes are added to a Proxmox cluster after Pulse was
initially configured, they weren't showing up in Settings. The
existing "Refresh" button only triggered network discovery, not
cluster membership re-detection.

Changes:
- Add POST /api/config/nodes/{id}/refresh-cluster endpoint
- Add "Refresh" button in cluster node panel in Settings
- Re-detect cluster membership and update stored endpoints

Related to #799
2025-12-02 22:01:00 +00:00
rcourtman
72af7bed5e style: Apply gofmt to 37 files
Standardize code formatting across test files and monitor.go.
No functional changes.
2025-12-02 17:21:48 +00:00
rcourtman
ec6133afd8 refactor: Remove duplicate IsPasswordHashed from auth package
The config package has a more robust IsPasswordHashed function that
handles truncated hashes. The auth package had a simpler duplicate
that was only used in tests. Removed the duplicate and its test
(already covered by config/config_utils_test.go).

Reduces deadcode findings from 7 to 6.
2025-12-02 17:19:07 +00:00
rcourtman
185e7098bd refactor: Remove duplicate isLoopback function from hostagent
The isLoopback function in internal/hostagent/agent.go was unused in
production code - it was a duplicate of the same function in
internal/hostmetrics/collector.go which is actively used.

Removed the dead code along with its associated tests to reduce
maintenance burden and improve code clarity.
2025-12-02 16:52:55 +00:00
rcourtman
c108cba8bb security: Add request body size limits to remaining API handlers
Add http.MaxBytesReader to 8 additional handlers to complete API
hardening against memory exhaustion attacks:

- guest_metadata.go: HandleUpdateMetadata (16KB)
- notification_queue.go: RetryDLQItem, DeleteDLQItem (8KB each)
- temperature_proxy.go: HandleRegister (8KB)
- host_agents.go: HandleReport (256KB)
- updates.go: HandleApplyUpdate (8KB)
- docker_metadata.go: HandleUpdateMetadata (16KB)
- system_settings.go: UpdateSystemSettings (64KB)

All API handlers that decode JSON request bodies now have size limits.
2025-12-02 16:47:13 +00:00
rcourtman
7b55564b62 security: Add request body size limits to API handlers
Add http.MaxBytesReader to 16 additional handlers to prevent memory
exhaustion attacks via oversized request bodies:

- docker_agents.go: HandleReport (512KB), HandleCommandAck (8KB),
  HandleSetCustomDisplayName (8KB)
- alerts.go: UpdateAlertConfig (64KB), BulkAcknowledgeAlerts (32KB),
  BulkClearAlerts (32KB)
- config_handlers.go: HandleAddNode, HandleTestConnection,
  HandleUpdateNode, HandleTestNodeConfig (32KB each),
  HandleVerifyTemperatureSSH, HandleExportConfig, HandleDiscoverServers,
  HandleSetupScriptURL (8KB each), HandleImportConfig (1MB),
  HandleUpdateMockMode (16KB)
2025-12-02 16:43:13 +00:00
rcourtman
ccc26624e8 security: Add request body size limits to notification handlers
Add http.MaxBytesReader limits to prevent memory exhaustion attacks:
- UpdateEmailConfig: 32KB limit
- UpdateAppriseConfig: 64KB limit
- CreateWebhook: 64KB limit
- UpdateWebhook: 64KB limit

This follows the pattern already used in system_settings.go for
SSH config validation.
2025-12-02 16:37:30 +00:00
rcourtman
0bcaa41499 test: Fix unreachable code warning in panic recovery test
Refactor the test to avoid unreachable code after panic by
checking a flag set before the panic instead of after. This
resolves the go vet warning while maintaining test coverage.
2025-12-02 16:30:31 +00:00
rcourtman
2bcdeea537 refactor: Use zerolog instead of fmt.Printf in config export
Replace raw fmt.Printf calls with structured zerolog logging for
consistency with the rest of the codebase. This improves log
formatting and enables proper log level filtering.
2025-12-02 16:27:54 +00:00
rcourtman
12f133f6f8 test: Add tests for SyncGuestBackupTimes and UpdateStorageBackupsForInstance
Add tests for the remaining uncovered State methods:
- SyncGuestBackupTimes: Tests backup time sync from storage and PBS backups
- UpdateStorageBackupsForInstance: Tests storage backup updates with instance isolation

Improves internal/models coverage from 89.6% to 95.6%.
2025-12-02 16:22:38 +00:00
rcourtman
b5a5fddaa3 test: Add tests for Ceph, backup, replication, and snapshot methods
Add tests for previously uncovered State methods:
- UpdateCephClustersForInstance
- UpdateBackupTasksForInstance
- UpdateReplicationJobsForInstance
- UpdateGuestSnapshotsForInstance

Improves internal/models coverage from 80.4% to 89.6%.
2025-12-02 16:20:11 +00:00
rcourtman
cbbb790284 test: Add more State method tests for coverage
Add tests for previously uncovered State methods:
- UpdatePhysicalDisks
- UpdateStorageForInstance
- UpdatePBSInstances / UpdatePBSInstance
- UpdatePMGInstances / UpdatePMGInstance

Improves internal/models coverage from 71.9% to 80.4%.
2025-12-02 16:17:04 +00:00
rcourtman
5b7e7a3133 test: Add tests for state connection health and backup methods
Add tests for previously uncovered State methods:
- SetConnectionHealth / RemoveConnectionHealth
- UpdatePBSBackups
- UpdatePMGBackups

Improves internal/models coverage from 67.0% to 71.9%.
2025-12-02 16:14:40 +00:00
rcourtman
36740bffe3 docs: Add godoc comments to more exported functions
Add missing godoc comments to:
- BuildGuestKey in alerts/alerts.go
- GenerateMockData in mock/generator.go
- NewDockerUpdater, NewAURUpdater in updates/adapter_installsh.go
- NewMockUpdater in updates/mock_updater.go
2025-12-02 16:03:57 +00:00
rcourtman
c019e4cd0e docs: Add godoc comments to exported functions
Add missing godoc comments to:
- NewRateLimiter and Allow in ratelimit.go
- SnapshotSyncStatus in temperature_proxy.go
- NewClient and GetVersion in pkg/pmg/client.go
2025-12-02 15:58:59 +00:00
rcourtman
25294da5d5 perf: Cache hostname lowercase in temperature proxy lookups
Pre-compute strings.ToLower(hostname) before loops that search for
matching PVE instances. Avoids repeated lowercasing in two functions.
2025-12-02 15:43:41 +00:00
rcourtman
6931fa34cd perf: Cache err.Error() in cluster node validation
Cache err.Error() result in two locations in config_handlers.go:
- TLS mismatch detection (3x calls to 1)
- Standalone node detection (2x calls to 1)
2025-12-02 15:41:18 +00:00
rcourtman
6a29e20b5e perf: Cache err.Error() in storage timeout error handling
Cache err.Error() result in two locations:
- monitor.go: storage query retry logic (2x calls to 1)
- monitor_polling.go: storage timeout handling (2x calls to 1)
2025-12-02 15:39:37 +00:00
rcourtman
5d2eca3660 perf: Cache err.Error() in disk monitoring error handling
Compute err.Error() once and reuse errStr instead of calling Error()
four times when checking disk monitoring error types.
2025-12-02 15:37:48 +00:00
rcourtman
9fc567dc2e perf: Cache lowercase RAID state in alerts processing
Compute strings.ToLower(array.State) once and reuse stateLower instead
of calling ToLower three times when checking RAID array status.
2025-12-02 15:35:32 +00:00
rcourtman
128dccf270 chore: Remove debug logging that exposed config JSON
Removed two DEBUG log statements that were logging full nodes config
JSON at Info level. This was verbose and potentially exposed sensitive
configuration data (credentials, tokens) in logs.
2025-12-02 15:32:02 +00:00
rcourtman
8f5b258424 perf: Cache lowercase error string in guest agent error handling
Compute strings.ToLower(errStr) once and reuse errStrLower instead of
calling ToLower three times on the same string in permission check.
2025-12-02 15:26:40 +00:00
rcourtman
f383cf8ddf perf: Remove redundant fmt.Sprintf in tempproxy contains function
The fmt.Sprintf("%v", s) call was pointless since s is already a string.
Removing this unnecessary conversion.
2025-12-02 15:24:40 +00:00
rcourtman
b47a04aa97 perf: Use strconv.Itoa instead of fmt.Sprintf for int conversion
strconv.Itoa is faster than fmt.Sprintf("%d", ...) because it doesn't
need to parse a format string. Changed 4 occurrences in monitoring
package where integers are converted to strings.
2025-12-02 15:21:41 +00:00
rcourtman
a965285738 perf: Pre-compile regexes in updates/version package
Move regex compilation from function bodies to package-level variables
to avoid recompilation when parsing version strings.

Affected regexes:
- semverRe: Matches semantic version format (X.Y.Z-prerelease+build)
- rcNumRe: Extracts RC number from prerelease strings

These are called multiple times during version comparison and update checks.
2025-12-02 15:14:15 +00:00
rcourtman
fd3c57377c perf: Pre-compile regexes in mdadm package
Move regex compilation from function bodies to package-level variables
to avoid recompilation on each RAID array check during polling cycles.

Affected regexes:
- mdDeviceRe: Matches md device names in /proc/mdstat
- slotRe: Matches device slot lines in mdadm --detail output
- speedRe: Extracts rebuild speed from /proc/mdstat
2025-12-02 15:11:04 +00:00
rcourtman
ac4e48fa4a fix: Properly show disabled storage status from Proxmox
Storage that is disabled in Proxmox (Datacenter > Storage > enabled=no)
was incorrectly showing as "available" in Pulse. The issue was that
Enabled/Active fields defaulted to true and were never set to false
from the per-node API response.

Now the model correctly initializes Enabled/Active from the Proxmox
per-node storage API response, and the status determination prioritizes
checking the disabled state first.

Related to #796
2025-12-02 15:03:40 +00:00
rcourtman
be23624592 refactor: Remove unreachable dead code branches
- parseDetail: Remove len(parts) != 2 check after SplitN(line, ":", 2)
  when we already verified line contains ":" (SplitN always returns 2)

Function improved from 96.4% to 98.1% coverage.
2025-12-02 15:00:26 +00:00
rcourtman
a0a473ada8 refactor: Remove unreachable dead code branches
- checkOrigin: Remove redundant same-origin check at line 155 that was
  already handled at line 116 (origin == requestOrigin)

Function improved from 95.1% to 97.4% coverage.
2025-12-02 14:56:35 +00:00
rcourtman
a647ffb219 refactor: Remove unreachable dead code branches
- Host.ToFrontend: Remove redundant h.DisplayName check after struct
  initialization already set host.DisplayName = h.DisplayName

Function now at 100% coverage.
2025-12-02 14:53:07 +00:00
rcourtman
c1d98e6aa8 refactor: Remove unreachable dead code branches
- errors.isRetryable: Convert final case to default (all ErrorType values covered)
- scheduler.SelectInterval: Remove bounds checks after mathematical computation
  that guarantees target ∈ [min, max]

Both functions now at 100% coverage.
2025-12-02 14:48:57 +00:00
rcourtman
2453198f62 refactor: Remove unreachable dead code branches
- firstForwardedValue: strings.Split always returns at least one element
- shouldRunBackupPoll: remaining is always >= 1 by math
- convertContainerDiskInfo: lowerLabel is never empty for non-rootfs

All three functions now at 100% coverage.
2025-12-02 14:41:53 +00:00
rcourtman
3d9c4f6da1 test: Add UpdateStatus not found test for notifications package 2025-12-02 14:26:17 +00:00
rcourtman
3f8455dfa9 test: Add DispatchDue enqueue error test for monitoring package 2025-12-02 14:21:25 +00:00
rcourtman
a5f263cf79 test: Add NewNotificationQueue invalid path test for notifications package 2025-12-02 14:17:05 +00:00
rcourtman
eb302e6d4e test: Add SessionStore.load legacy format tests for API package 2025-12-02 14:12:32 +00:00
rcourtman
e7fa996e03 test: Add CSRFTokenStore.load format tests for API package
Cover legacy JSON format migration and current format with nil/expired
entries. Improves load function coverage from 67.9% to 100%.
2025-12-02 14:07:00 +00:00
rcourtman
daafb51493 test: Add CheckAuth tests for API package
Add tests for sliding expiration session validation and no-auth
configured scenarios. These test explicit paths for better coverage
documentation even though they were already exercised indirectly.
2025-12-02 13:57:23 +00:00
rcourtman
2f203bf2d9 test: Add CheckCSRF valid token test for 100% coverage
Test the success path where a valid CSRF token is provided with a
matching session. This covers the final branch in CheckCSRF.
2025-12-02 13:51:27 +00:00
rcourtman
e1ff07fd9f test: Add singleAlertTemplate type coverage tests
Cover io type (formats as "I/O") and custom type (uses titleCase)
branches that were previously untested in the email template.
2025-12-02 13:45:49 +00:00
rcourtman
4797e8d76a test: Add ValidateWebhookURL edge case tests for notifications package
Cover empty URL, invalid scheme, missing hostname, cloud metadata
endpoints, loopback variants, and IPv6 link-local addresses.
2025-12-02 13:41:34 +00:00
rcourtman
50769e12ea test: Add HandleSetupScript PBS path tests for API package
Cover the PBS script generation branch that was previously untested.
Verifies PBS-specific content, auth token handling, and placeholder host.
2025-12-02 13:36:23 +00:00
rcourtman
28533975f6 test: Add CheckAuth tests for API package
Cover proxy auth headers, OIDC session validation, and session cookie
paths that were previously untested.
2025-12-02 13:32:21 +00:00
rcourtman
d058b2ab96 test: Add CheckProxyAuth tests for API package
Add comprehensive direct tests for the CheckProxyAuth function covering:
- Not configured (returns false)
- Invalid secret (returns false)
- Missing secret header (returns false)
- Valid secret without user header configured (returns true, admin)
- Missing user header when configured (returns false)
- Valid auth with username (returns true with username)
- Role checking with empty roles header (defaults to admin)
- Role checking with admin role present (returns admin=true)
- Role checking without admin role (returns admin=false)
- Custom role separator (comma instead of pipe)
- Role with whitespace (trimmed correctly)

Coverage: CheckProxyAuth 89.3% → 100%
2025-12-02 13:28:02 +00:00
rcourtman
d219d9965d test: Add ValidateSession tests for API package
Add comprehensive tests for the ValidateSession wrapper function covering:
- Non-existent token (returns false)
- Empty token (returns false)
- Valid token (returns true)
- Expired token (returns false)

The ValidateSession function is a simple wrapper around the SessionStore's
ValidateSession method, but having direct tests ensures the wrapper is
exercised and documents its expected behavior.

Coverage: ValidateSession 0% → 100%
2025-12-02 13:22:45 +00:00
rcourtman
ef6a370144 test: Add ensureScope tests for API package
Add comprehensive tests for the ensureScope function covering:
- Empty scope parameter (always allows access)
- No token in context (session-based request, allows access)
- Token with matching scope (allows access)
- Token with multiple scopes including required one (allows access)
- Token missing required scope (rejects with 403)
- Token with empty scopes (defaults to wildcard, allows access)
- Rejection returns proper JSON response format

Coverage: ensureScope 0% → 100%
Coverage: API package 32.1% → 32.2%
2025-12-02 13:19:11 +00:00
rcourtman
301338d800 test: Add sendResolvedEmail tests for notifications package
Add comprehensive tests for the sendResolvedEmail function covering:
- Empty alert list (returns error)
- Nil alert list (returns error)
- All nil alerts (returns error from content builder)
- Single alert (exercises email sending path)
- Multiple alerts (tests grouped notification)
- Mixed nil and valid alerts (filters correctly)
- Zero resolved time (handles gracefully)

Also improves buildResolvedNotificationContent coverage as a collateral
benefit since sendResolvedEmail calls it internally.

Coverage: sendResolvedEmail 0% → 100%
Coverage: buildResolvedNotificationContent → 100%
Coverage: notifications package 58.3% → 58.6%
2025-12-02 13:14:22 +00:00
rcourtman
d970055532 test: Add RequireAuth tests for API package
Add comprehensive tests for the RequireAuth middleware covering:
- No auth configured (allows access by design)
- API-only mode (rejects requests without token)
- API-only mode (accepts valid X-API-Token)
- Basic auth with invalid credentials
- Basic auth JSON vs plain text error responses
- Valid basic auth (allowed)
- Proxy auth (allowed)
- Proxy auth with invalid secret (rejected)
- Bearer token with basic auth configured (allowed)
- Invalid Bearer token (rejected)

Coverage: RequireAuth 7.1% → 78.6%
Coverage: CheckAuth 66.9% → 69.1%
Coverage: API package 31.9% → 32.1%
2025-12-02 13:09:48 +00:00
rcourtman
1073c511b3 test: Add RequireAdmin tests for API package
Add comprehensive tests for the RequireAdmin middleware covering:
- No auth configured (allows access by design)
- API-only mode (rejects requests without token)
- Basic auth with invalid credentials
- Proxy auth with admin role (allowed)
- Proxy auth with non-admin role (forbidden)
- Proxy auth with invalid secret (unauthorized)
- Proxy auth without role header (defaults to admin)
- Proxy auth with custom role separator
- Proxy auth with spaces in roles (trimmed)
- Basic auth authenticated users (allowed as admin)
- JSON vs plain text error responses based on path/Accept header

Also improves CheckProxyAuth coverage as a side effect.

Coverage: RequireAdmin 20.8% → 87.5%
Coverage: CheckProxyAuth 0.0% → 89.3%
Coverage: API package 30.9% → 31.9%
2025-12-02 13:06:06 +00:00
rcourtman
71e15886ed test: Add isRequestAuthenticated tests for API package
Add comprehensive tests for the isRequestAuthenticated function covering:
- Nil inputs (config, request, both)
- Basic auth (valid, invalid password, invalid username, malformed base64, missing colon)
- API token via X-API-Token header
- API token via Bearer authorization header (case insensitive)
- Invalid/empty/whitespace API tokens
- No auth configured scenarios
- Empty session cookie handling

Coverage: isRequestAuthenticated 26.1% → 82.6%
Coverage: API package 30.7% → 30.9%
2025-12-02 12:59:18 +00:00
rcourtman
cf6149e884 test: Add CheckCSRF tests for API package
Add comprehensive tests for the CheckCSRF function covering:
- Safe methods (GET, HEAD, OPTIONS) bypass
- API token authentication bypass
- Basic auth bypass
- No session cookie handling
- Missing CSRF token rejection with new token issuance
- Invalid CSRF token rejection with new token issuance
- CSRF token from FormValue
- Unsafe methods (POST, PUT, DELETE, PATCH) enforcement

Coverage: CheckCSRF 32.0% → 96.0%
Coverage: API package 30.5% → 30.7%
2025-12-02 12:53:32 +00:00
rcourtman
5deca850d4 test: Add saveHistoryWithRetry tests for alerts package
Add comprehensive tests for the saveHistoryWithRetry function covering:
- Backup file creation from existing history
- Empty history serialization
- Single retry success
- Read-only directory failure with retries
- Concurrent saves with serialization via saveMu
- Snapshot isolation during save

Coverage: saveHistoryWithRetry 58.6% → 86.2%
Coverage: alerts package 87.4% → 87.8%
2025-12-02 12:49:27 +00:00
rcourtman
cd33c577f8 test: Add resolvePublicURL tests for API package
Add comprehensive tests for the resolvePublicURL function covering:
- Configured PublicURL (simple, trailing slashes, ports, whitespace)
- Request-derived URL (HTTP, HTTPS via TLS, X-Forwarded-Proto)
- No host fallback (with/without frontend port)
- Nil request handling

Coverage: resolvePublicURL 12.5% → 100%
Coverage: API package 30.3% → 30.5%
2025-12-02 12:45:04 +00:00
rcourtman
80739cce94 test: Add rescheduleTask tests for monitoring package
Add comprehensive tests for the rescheduleTask function covering:
- Nil taskQueue handling (early return)
- Successful task outcome (regular rescheduling)
- Transient failure with backoff
- Non-transient failure routing to dead letter queue
- Exceeded retry attempts routing to dead letter queue
- No outcome uses default interval
- PBS and PMG instance type intervals
- Adaptive polling max interval capping
- Existing interval preservation

Coverage: rescheduleTask 32.1% → 58.9%
Coverage: monitoring package 52.8% → 53.5%
2025-12-02 12:38:50 +00:00
rcourtman
2842dded28 test: Add getGuestThresholds tests for alerts package
Add comprehensive tests for the getGuestThresholds function covering:
- Default threshold application
- Guest-specific overrides
- Custom rule filter matching
- Override precedence over custom rules
- Priority-based rule selection
- Disabled rules handling
- Disabled override handling
- DisableConnectivity propagation from overrides and rules
- Legacy CPU threshold conversion
- Legacy ID migration (clustered and standalone VMs)
- Container type support
- All metric thresholds application

Coverage: getGuestThresholds 40.2% → 77.6%
2025-12-02 12:35:07 +00:00
rcourtman
a4e3fe65b8 test: Add preserveAlertState, checkPMGQuarantineBacklog, LoadActiveAlerts tests
Add comprehensive tests for three low-coverage functions:
- preserveAlertState: nil handling, state preservation from existing alerts,
  ackState fallback, new alert handling
- checkPMGQuarantineBacklog: nil quarantine handling, warning/critical
  thresholds, growth rate alerts, alert updates, virus quarantine
- LoadActiveAlerts: missing file, valid file loading, old alert filtering,
  old acknowledged alert filtering, ack state restoration, invalid JSON,
  duplicate alert handling

Coverage improvements:
- preserveAlertState: 63.6% → 100%
- checkPMGQuarantineBacklog: 12.9% → 100%
- checkQuarantineMetric: 0% → 93.1%
- LoadActiveAlerts: 26.2% → 80.0%
- Alerts package: 83.5% → 86.6%
2025-12-02 12:22:14 +00:00
rcourtman
2133b25bb7 test: Add performCleanup tests for notifications queue
Add 4 tests covering the performCleanup function:
- cleanup removes old completed entries (>7 days)
- cleanup removes old DLQ entries (>30 days)
- cleanup removes old audit logs (>30 days)
- cleanup with empty database (no panic)

performCleanup coverage: 0% → 87.0%
Notifications package: 57.3% → 58.3%
2025-12-02 12:16:55 +00:00
rcourtman
a6f4fc7bc0 test: Add GetQueue, addWebhookDelivery, GetWebhookHistory tests
Tests for NotificationManager accessor and helper functions.
Covers queue retrieval, webhook delivery tracking, history trimming
to max 100 entries, and copy-on-read semantics. Notifications 56.6%→57.3%.
2025-12-02 12:10:29 +00:00
rcourtman
f184174f2b test: Add HistoryManager tests for alerts package
New history_test.go with 24 tests covering GetStats, getFileSize,
AddAlert, GetHistory, GetAllHistory, RemoveAlert, ClearAllHistory,
cleanOldEntries, saveHistory, loadHistory. Alerts package 83.6%→84.0%.
2025-12-02 12:06:53 +00:00
rcourtman
fc96ba7b69 test: Add WaitNext and key() tests for TaskQueue
Tests cover context cancellation, immediately due tasks, waiting for
future tasks, empty queue timeout, and multiple task priority ordering.
WaitNext coverage 0%→92.3%, key() 0%→100%. Monitoring package 52.3%→52.9%.
2025-12-02 12:02:13 +00:00
rcourtman
e63c297ca3 test: Add BuildPlan, FilterDue, DispatchDue, LastScheduled tests
Comprehensive tests for AdaptiveScheduler methods covering empty inventory,
single/multiple instances, priority ordering, interval clamping, task caching,
nil receiver handling, and task filtering. Monitoring package 51.4%→52.3%.
2025-12-02 11:59:37 +00:00
rcourtman
ea120b78d7 test: Add RecordNodeResult, RecordQueueWait, SetQueueDepth tests
Improves metrics.go coverage to 100%. Added comprehensive tests for
node-level poll metrics, queue wait time recording, and queue depth
setting with edge cases (nil receiver, negative values, label normalization).
2025-12-02 11:57:05 +00:00
rcourtman
47d0fb5a44 test: Add dispatchAlert tests (55.6%→77.8%)
Add TestDispatchAlert with 8 test cases covering:
- Returns false when onAlert callback is nil
- Returns false when alert is nil
- Returns false when activation state is pending
- Returns false when activation state is snoozed
- Returns false for monitor-only alerts
- Dispatches synchronously when async is false
- Dispatches asynchronously when async is true
- Clones alert before dispatch

Alerts package coverage: 83.4%→83.5%
2025-12-02 11:47:24 +00:00
rcourtman
b3bf63d3c7 test: Add CheckStorage tests (52.4%→92.9%)
Add comprehensive TestCheckStorageComprehensive with 11 test cases covering:
- Returns early when alerts disabled
- DisableAllStorage clears existing usage and offline alerts
- Override with Disabled clears alerts
- Usage threshold checking
- Override threshold applied correctly
- Skips usage check when offline/unavailable/zero usage
- Offline status creates alert after confirmations
- Unavailable status creates alert
- Clears offline alert when back online

Alerts package coverage: 82.4%→83.4%
2025-12-02 11:43:56 +00:00
rcourtman
9127b27f4c test: Add CheckPMG tests (0%→100%)
Add comprehensive TestCheckPMGComprehensive with 9 test cases covering:
- Returns early when alerts disabled
- DisableAllPMG clears all PMG alert types (queue-total, queue-deferred,
  queue-hold, oldest-message, offline)
- Override with Disabled clears alerts
- DisableAllPMGOffline clears offline alert
- Offline status creates alert after confirmations
- Connection health error triggers offline alert
- Connection health unhealthy triggers offline alert
- Clears offline alert when back online
- Skips metrics when PMG is offline

Alerts package coverage: 81.5%→82.4%
2025-12-02 11:40:53 +00:00
rcourtman
073d5ffa55 fix: Use --ctid instead of --standalone --http-mode in quick-setup command
The quick-setup command for temperature monitoring was generating
--standalone --http-mode which is meant for Docker deployments. This
confused users trying to set up multi-server Proxmox monitoring.

Now uses --ctid which works for both local and remote Proxmox hosts.
The installer detects when the container doesn't exist locally and
installs in "host monitoring only" mode automatically.

If we can determine the actual CTID from the host proxy summary,
we use it; otherwise we show <PULSE_CTID> for the user to replace.

Related to #785
2025-12-02 11:38:47 +00:00
rcourtman
9f174be20b test: Add CheckPBS tests (0%→98.3%)
Add comprehensive TestCheckPBSComprehensive with 12 test cases covering:
- Returns early when alerts disabled
- DisableAllPBS clears existing CPU/memory/offline alerts
- Override with Disabled clears alerts
- DisableAllPBSOffline clears offline alert
- CPU threshold checking when online
- Memory threshold checking when online
- Skips metrics when PBS is offline
- Override thresholds applied correctly
- Offline status creates alert after confirmations
- Connection health error triggers offline alert
- Connection health unhealthy triggers offline alert
- Clears offline alert when back online

Alerts package coverage: 80.0%→81.5%
2025-12-02 11:38:36 +00:00
rcourtman
13f5ca4018 test: Add CheckHost tests (49.6%→98.3%)
Add comprehensive TestCheckHostComprehensive with 17 test cases covering:
- Empty host ID early return
- Alerts disabled early return
- DisableAllHosts clears existing alerts
- Override with Disabled clears alerts
- CPU/Memory/Disk threshold nil clears alerts
- RAID degraded/rebuilding/healthy states
- RAID with failed devices triggers critical alert
- RAID resync triggers rebuilding alert
- Existing RAID alert not duplicated (preserves start time)
- Override thresholds applied correctly
- Multiple disks handling
- Offline alert cleared when host comes online
- Tags included in metadata

Alerts package coverage: 78.6%→80.0%
2025-12-02 11:34:20 +00:00
rcourtman
f4e3f625e7 test: Add CheckGuest tests (41.4%→97.4%)
Cover all CheckGuest branches:
- Early return when alerts disabled
- Early return when all guests disabled
- VM and Container type handling
- Unsupported guest type returns early
- pulse-no-alerts tag suppresses alerts
- Stopped guest triggers powered-off check
- DisableAllGuestsOffline clears tracking
- Paused guest clears powered-off alert
- Non-running guest clears metric alerts
- Running guest clears powered-off alert
- Disabled thresholds clear existing alerts
- CPU, memory, disk metric checks
- Individual disk checks (mountpoint, device, index fallback)
- Skips disk with zero total or negative usage
- I/O metrics (diskRead, diskWrite, networkIn, networkOut)
- pulse-relaxed tag applies relaxed thresholds

Alerts package coverage: 76.0%→78.6%
2025-12-02 11:27:32 +00:00
rcourtman
4ceb4f9a35 test: Add CheckNode tests (31%→100%)
Cover all CheckNode branches:
- Early return when alerts disabled
- DisableAllNodes clears existing alerts
- DisableNodesOffline clears tracking
- Offline/connection error/failed triggers offline check
- Online node clears offline alert
- Online node triggers metric checks
- Offline node skips metric checks
- Override thresholds applied correctly
- Temperature with package temp and max fallback
- Temperature skipped when unavailable/nil/no threshold
- Memory and disk metric checks

Alerts package coverage: 75.2%→76.0%
2025-12-02 11:24:04 +00:00
rcourtman
9791fc07cb test: Add suppressGuestAlerts and guestHasMonitorOnlyAlerts tests
Coverage improvements:
- suppressGuestAlerts: 37% -> 96.3%
- guestHasMonitorOnlyAlerts: 40% -> 90%

Tests cover:
- No alerts returns false
- Exact ResourceID match clears
- Prefix match (e.g., "vm100/disk1") clears
- All auxiliary maps cleared (pending, recent, suppressed, rateLimit)
- Multiple alerts cleared
- Monitor-only detection via metadata (bool and string types)
2025-12-02 11:14:30 +00:00
rcourtman
f661c5a6a8 test: Add applyThresholdOverride tests
Coverage for applyThresholdOverride: 50% -> 93.2%

Tests cover:
- Empty override returns base unchanged
- Disabled/DisableConnectivity flag overrides
- Modern CPU threshold override
- Legacy CPU threshold conversion
- Modern takes precedence over legacy
- Multiple metrics override
- Note override, clearing, trimming
- All legacy metric types (Memory, Disk, etc.)
- Temperature and Usage override
- ensureHysteresisThreshold Clear value filling
2025-12-02 11:08:58 +00:00
rcourtman
ed118c973f test: Add ClearActiveAlerts test with existing alerts
Coverage for ClearActiveAlerts: 16% -> 92%

Tests verify all internal maps are properly cleared when alerts exist:
- activeAlerts, pendingAlerts, recentAlerts
- suppressedUntil, alertRateLimit
- nodeOfflineCount, offlineConfirmations
- dockerOfflineCount, dockerStateConfirm
- ackState, recentlyResolved
2025-12-02 11:01:54 +00:00
rcourtman
219c568649 test: Add CheckDiskHealth normal path tests
Coverage for CheckDiskHealth: 51% -> 98%

Tests cover:
- Healthy disk (PASSED/OK) creates no alert
- Failed non-Samsung disk creates critical alert
- Alert cleared when disk health recovers
- Low wearout (<10%) creates warning alert
- Wearout alert updates on subsequent checks
- Wearout alert cleared when wearout >= 10%
- Empty/UNKNOWN health creates no alert
2025-12-02 10:59:48 +00:00
rcourtman
c04d559700 test: Add Docker container restart loop alert tests
Coverage for checkDockerContainerRestartLoop: 53.5% -> 95.3%

Tests cover:
- First check initializes tracking without alert
- Stable restart count doesn't alert
- Restarts under threshold (<=3) don't alert
- Restart loop threshold (>3) triggers critical alert
- Recovery after window expires clears alert
- Incremental restart accumulation
- Alert StartTime preservation on updates
2025-12-02 10:54:51 +00:00
rcourtman
b6624e32cf test: Add Docker container health and OOM kill alert tests
Coverage improvements:
- checkDockerContainerHealth: 21.1% -> 94.7%
- checkDockerContainerOOMKill: 19.2% -> 96.2%

Tests cover:
- Health states (healthy, empty, none, starting, unhealthy, degraded)
- Health alert recovery when container becomes healthy
- OOM kill detection (exit code 137)
- OOM alert deduplication (repeated 137 doesn't re-alert)
- OOM alert clearing when container recovers or exits with different code
2025-12-02 10:49:42 +00:00
rcourtman
1ed8b18c12 fix: Deadlock in CancelByAlertIDs and add tests
Fixed deadlock where CancelByAlertIDs held nq.mu.Lock() and then called
UpdateStatus() which also tried to acquire the same lock. Now uses
direct SQL while holding the lock.

Tests added for CancelByAlertIDs:
- No matching notifications (notification stays pending)
- Matching notification cancelled
- Multiple alerts with partial match (any match cancels)

Coverage: CancelByAlertIDs 65.7% -> 81.1%
2025-12-02 10:40:07 +00:00
rcourtman
5ef4587767 test: Add queue IncrementAttempt and GetQueueStats tests
Coverage improvements:
- IncrementAttempt: 0% -> 85.7%
- GetQueueStats: 0% -> 87.5%

Tests verify attempt counter increments correctly and queue stats
aggregate notification counts by status.
2025-12-02 10:31:00 +00:00
rcourtman
e27717f1a2 test: Add secure webhook client tests for redirect handling
Tests SSRF protection in webhook client:
- Redirect limit enforcement (max 3)
- Blocking redirects to private networks (10.x, 192.168.x, 172.16.x)
- Blocking redirects to link-local addresses (169.254.x)
- Allowing valid redirects to allowlisted servers

Coverage: createSecureWebhookClient 18.2% -> 100%
2025-12-02 10:26:34 +00:00
rcourtman
9118344355 fix: Isolate alerts tests with temp directories to prevent flaky failures
Tests using NewManager() were sharing /etc/pulse/alerts, causing race
conditions when running in parallel. Added newTestManager(t) helper that
creates isolated temp directories for each test.
2025-12-02 10:21:03 +00:00
rcourtman
350d21c80d test: Add diagnostics function tests for error handling
Add comprehensive tests for untested diagnostics functions:

- fingerprintPublicKey: 14 test cases covering empty/whitespace input,
  invalid key formats, truncated/malformed keys, and valid ED25519 keys

- countLegacySSHKeys: 8 test cases covering non-existent directories,
  empty directories, files without id_ prefix, multiple key types,
  and directory filtering (subdirectories not counted)

- resolveUserName: 4 test cases covering UID 0 (root), current user,
  non-existent UID fallback, and max uint32 boundary

- resolveGroupName: 4 test cases covering GID 0 (root/wheel), current
  group, non-existent GID fallback, and max uint32 boundary

Coverage: fingerprintPublicKey 0% -> 100%, countLegacySSHKeys 0% -> 100%,
resolveUserName 0% -> 100%, resolveGroupName 0% -> 100%
2025-12-02 03:39:52 +00:00
rcourtman
b053a2848b fix: Update TestPublicURLDetectionUsesForwardedHeaders for proxy hardening
The test was failing after commit d6cbfc23 added security hardening
that requires authentication and trusted proxy configuration for
X-Forwarded-* headers to be read during public URL detection.

- Add API token authentication to the test request
- Configure 127.0.0.1 as trusted proxy for the test
- Add export_test.go with ResetTrustedProxyConfigForTests() to allow
  external tests to reset the trusted proxy configuration
2025-12-02 03:16:52 +00:00
rcourtman
201f613ac3 test: Add sendNotificationsDirect email and apprise tests
Test email enabled and apprise enabled code paths.
Coverage: 66.7% → 100.0%
2025-12-02 03:08:35 +00:00
rcourtman
37ec6c3a93 test: Add scanNotification DLQ timestamp test
Test scanNotification with CompletedAt and LastAttempt populated
via DLQ path. Coverage: 61.9% → 81.0%
2025-12-02 03:04:37 +00:00
rcourtman
ae54cfad8c test: Add processNotification tests for all code paths
Test cancelled notification, no processor, success, and failure paths.
Coverage: 50.0% → 80.0%
2025-12-02 03:01:17 +00:00
rcourtman
ca7da7c18f test: Add CancelByAlertIDs empty input and no-match tests
Test early return for empty alertIDs and happy path with empty queue.
Coverage: 62.9% → 65.7%
2025-12-02 02:58:10 +00:00
rcourtman
7a1c9ff53f test: Add SaveNodesConfigAllowEmpty test and document deadlock
Add test for SaveNodesConfigAllowEmpty which permits explicit
deletion of all nodes. Document deadlock bug in saveNodesConfig
where empty config protection tries to call LoadNodesConfig
while holding write lock.
2025-12-02 02:54:49 +00:00
rcourtman
d0fc62d45f test: Add LoadNodesConfig PBS/PMG migration tests
Test PBS and PMG token clearing and host normalization migrations.
Coverage: 61.4% → 76.3%
2025-12-02 02:46:47 +00:00
rcourtman
6d1eb44f7b test: Add LoadEmailConfig encrypted round-trip test
Test Save+Load with encryption enabled to cover success path
after decryption. Coverage: 58.8% → 88.2%
2025-12-02 02:43:49 +00:00
rcourtman
3c1ae26166 test: Add LoadWebhooks migration and error path tests
Cover unencrypted .enc file migration fallback and legacy file
with invalid JSON graceful handling.
Coverage: 67.9% → 75.0%
2025-12-02 02:39:04 +00:00
rcourtman
9eb7c59a4d test: Add SaveAlertConfig host defaults normalization tests
Cover nil HostDefaults initialization (CPU/Memory/Disk) and clear
threshold computation when clear=0 but trigger is set.
Coverage: 68.2% → 75.3%
2025-12-02 02:37:01 +00:00
rcourtman
9027ab359b test: Add StageFile transaction tests
Cover success path, already committed error, replacing existing staged
file, and empty basename edge case.
2025-12-02 02:34:20 +00:00
rcourtman
6cb12bd048 test: Add ImportConfig error path tests
Cover empty passphrase, invalid base64, wrong passphrase decryption
failure, and invalid JSON content error paths.
Coverage: 66.7% → 73.7%
2025-12-02 02:32:06 +00:00
rcourtman
0d482f9d63 test: Add DiscoveryConfig UnmarshalJSON tests
Cover invalid JSON error path, modern field parsing, legacy field
parsing, and empty object default handling.
Coverage: 60% → 88.9%
2025-12-02 02:29:38 +00:00
rcourtman
071ccc44ec test: Add ProcessQueuedNotification error path tests
Cover invalid config JSON for email, webhook, and apprise types,
plus unknown notification type handling.
Coverage: 63.3% → 83.3%
2025-12-02 02:26:25 +00:00
rcourtman
7a63cf3be9 test: Add sendNotificationsDirect tests
Cover disabled paths: all channels disabled, webhook disabled,
multiple webhooks with mixed enabled state.
Coverage: 44.4% → 66.7%
2025-12-02 02:21:46 +00:00
rcourtman
ea04e4faae test: Add sendHTMLEmailWithError tests
Cover email sending paths: empty To uses From as recipient,
nil email manager creates new one, existing manager config updates.
Coverage: 57.9% → 89.5%
2025-12-02 02:19:49 +00:00
rcourtman
9768316e07 test: Add sendGroupedApprise error path tests
Add 3 tests for Apprise notification error handling:
- No alerts returns error
- Not enabled returns error
- Empty payload (all nil alerts) returns error

Coverage: 56.2% → 75.0%
2025-12-02 02:14:13 +00:00
rcourtman
42e7359506 test: Add describeInstancesForScheduler tests
Add 6 tests for instance descriptor generation:
- No clients returns nil
- PVE only with sorted order
- PBS only
- PMG only
- All types combined
- Nil scheduler/stalenessTracker safety

Coverage: 60.7% → 62.5%
2025-12-02 02:11:14 +00:00
rcourtman
de90519b21 test: Add handleHealth method tests
Add 2 tests for health endpoint:
- POST/PUT/DELETE/PATCH return 405 Method Not Allowed
- HEAD is allowed (same as GET)

Coverage: 50% → 83.3%
2025-12-02 02:09:04 +00:00
rcourtman
2d09c28129 test: Add recordTaskResult tests
Add 6 tests for polling task result recording:
- Nil monitor safety check
- Success case resets counters
- Failure case increments counters
- Consecutive failures tracking
- Success resets failure state
- Nil internal maps don't panic

Coverage: 53.7% → 97.6%
2025-12-02 02:06:08 +00:00
rcourtman
67d322c456 test: Add ApplyHostReport error path tests
Add 4 tests for error and edge cases:
- Missing hostname returns error
- Whitespace-only hostname returns error
- Nil hostTokenBindings map is initialized
- Fallback identifier generation

Coverage: 63.7% → 70.8%
2025-12-02 02:03:03 +00:00
rcourtman
7c94f3001e test: Add ApplyDockerReport error path tests
Add 4 tests for error conditions:
- Missing identifier (no agent ID or hostname)
- Removed host rejection
- Token bound to different agent
- Missing hostname

Coverage: 63.0% → 69.5%
2025-12-02 02:00:06 +00:00
rcourtman
781f72c953 test: Add RemoveHostAgent error path tests
Add 4 tests for uncovered branches:
- Empty/whitespace hostID returns error
- Host not found returns synthetic host
- No token binding (token exists but not bound)
- Nil alertManager doesn't panic

Coverage: 64.3% → 78.6%
2025-12-02 01:56:50 +00:00
rcourtman
5ff69a7e35 test: Add adminBypassEnabled tests
Add 5 tests to cover all branches:
- Not requested (ALLOW_ADMIN_BYPASS != "1")
- Enabled with PULSE_DEV=true
- Enabled with NODE_ENV=development
- Case-insensitive NODE_ENV check
- Declined when outside dev mode

Coverage: 40% → 100%
2025-12-02 01:53:55 +00:00
rcourtman
7ed8ef2074 test: Add loadTrustedProxyCIDRs tests
Cover invalid CIDR, invalid IP, IPv6, and empty entry handling (48% to 100%)
2025-12-02 01:48:41 +00:00
rcourtman
24fbce1281 test: Add LogAuditEvent tests
Cover success and failure logging branches (66.7% to 100%)
2025-12-02 01:46:27 +00:00
rcourtman
8f42156781 test: Add SecurityHeadersWithConfig tests
Cover all CSP/X-Frame-Options embedding configurations (57.1% to 100%)
2025-12-02 01:44:22 +00:00
rcourtman
07997b3516 test: Add filesystem error tests for SessionStore
Cover saveUnsafe (57.9% to 89.5%) and load (55.6% to 74.1%) error paths
2025-12-02 01:40:54 +00:00
rcourtman
21b69607f0 test: Add filesystem error tests for CSRFTokenStore
Cover saveUnsafe (57.9% to 89.5%) and load (50.0% to 67.9%) error paths
2025-12-02 01:38:49 +00:00
rcourtman
999f19beed test: Add filesystem error tests for RecoveryTokenStore.saveUnsafe
Cover MkdirAll, WriteFile, and Rename error paths (46.7% to 86.7%)
2025-12-02 01:36:21 +00:00
rcourtman
b3f88d7a8c test: Add edge case tests for HandleSetupScript
Tests method not allowed, missing type parameter, and invalid host
parameter error paths (71.4% to 79.2% coverage).
2025-12-02 01:11:57 +00:00
rcourtman
c080a6beb6 test: Add DNS resolution failure test for ValidateWebhookURL
Tests the error path when webhook hostname cannot be resolved
(78.1% to 81.2% coverage).
2025-12-02 01:09:03 +00:00
rcourtman
7d3de1bbcc test: Add invalid PEM data test for newOIDCHTTPClient
Tests the error path when a CA bundle file contains non-PEM data
(81.8% to 86.4% coverage).
2025-12-02 01:00:06 +00:00
rcourtman
1a595b3b2e test: Add edge cases for UniversalRateLimitMiddleware
Cover nil config initialization and static asset bypass paths.
Coverage: UniversalRateLimitMiddleware 87.5% -> 100%
2025-12-02 00:54:37 +00:00
rcourtman
c57c07f827 test: Add edge case for initializeBootstrapToken error path
Cover loadOrCreateBootstrapToken failure path.
Coverage: initializeBootstrapToken 92% -> 100%
2025-12-02 00:51:44 +00:00
rcourtman
a5f0482d97 test: Add edge cases for HandleLookup error paths
Cover method-not-allowed and missing lookup parameter paths.
Coverage: HandleLookup 88.4% -> 97.7%
2025-12-02 00:49:16 +00:00
rcourtman
44b835ad15 test: Add critical-only grouped alert template case
Test multiple critical alerts without warnings to cover the
"critical > 0" only branch in subject line generation.

Coverage: 97.7% → 100%
2025-12-02 00:40:02 +00:00
rcourtman
96bf0b0ca6 test: Add edge cases for buildApprisePayload
- Test nil alerts in list are filtered out
- Test all-nil alert list returns empty
- Test multiple alerts changes title format

Coverage: 88.9% → 100%
2025-12-02 00:37:28 +00:00
rcourtman
296a520d81 test: Add edge case for extractTelegramChatID URL parse error
Test URL with control characters triggers url.Parse error path.

Coverage: 92.9% → 100%
2025-12-02 00:31:50 +00:00
rcourtman
890a2f792d test: Add edge case for NormalizeAppriseConfig low timeout
Test TimeoutSeconds value between 1-4 clamps to minimum of 5.

Coverage: 97.4% → 100%
2025-12-02 00:29:12 +00:00
rcourtman
6777257a7a test: Add edge cases for normalizeRequestedScopes
- Test blank scope identifier returns error
- Test wildcard-only input returns wildcard scope

Coverage: 89.7% → 96.6% (remaining 3.4% is defensive
unreachable code path)
2025-12-02 00:19:20 +00:00
rcourtman
e07bd834b6 Filter virtual/system filesystems from host disk display
Host disk bars were showing virtual filesystems like tmpfs, /dev, /run,
/sys, and Docker overlay mounts. These clutter the UI and don't represent
meaningful disk usage.

Changed from `shouldIgnoreReadOnlyFilesystem` (read-only only) to the
full `fsfilters.ShouldSkipFilesystem` which also excludes:
- Virtual FS types: tmpfs, devtmpfs, sysfs, proc, cgroup, etc.
- Special mountpoints: /dev, /proc, /sys, /run, /var/lib/docker, /snap
- Network filesystems: fuse, nfs, cifs, etc.

Related to #790
2025-12-02 00:16:39 +00:00
rcourtman
b5d42f6e2e test: Add edge case for ensureSettingsWriteScope valid scope
Tests the code path when an API token has the settings:write scope,
which allows the operation to proceed.
2025-12-02 00:13:32 +00:00
rcourtman
8597eca010 Fix backup indicator being reset when VMs/Containers are re-polled
UpdateVMsForInstance and UpdateContainersForInstance were replacing
guest data without preserving the LastBackup field that was populated
by SyncGuestBackupTimes. This caused backup indicators to always show
"no backup found" since the LastBackup would be wiped every time
guests were polled (which happens more frequently than backup polling).

Now both functions preserve LastBackup from existing data when the
incoming guest data has a zero value.

Related to #762
2025-12-02 00:12:31 +00:00
rcourtman
9baf99d32a test: Add edge cases for isTrustedProxyIP and GetClientIP
Tests empty string, invalid IP, and IP not matching CIDR for
isTrustedProxyIP. Also adds tests for GetClientIP empty RemoteAddr
and X-Real-IP fallback paths.
2025-12-02 00:09:23 +00:00
rcourtman
02419827b6 test: Add tests for hostAgentSearchCandidates parameter variants
Tests all code paths: strict mode (both params), platform only,
and no params (generic paths).
2025-12-02 00:03:19 +00:00
rcourtman
7407447bbf test: Add edge case for handleServerInfo method not allowed
Tests that POST requests to /api/server/info return 405.
2025-12-02 00:01:17 +00:00
rcourtman
4751f57187 test: Add edge case for capturePublicURLFromRequest nil inputs
Tests the early return paths when router, request, or config are nil.
2025-12-01 23:59:17 +00:00
rcourtman
b9f9077496 test: Add edge case for canCapturePublicURL nil inputs
Tests the early return paths when config or request are nil.
2025-12-01 23:56:59 +00:00
rcourtman
f0688db9af test: Add edge case for recovery token load read error
Tests the error logging path when os.ReadFile fails with an error
other than ErrNotExist. Uses a directory in place of the file.
2025-12-01 23:54:42 +00:00
rcourtman
347d6b1cbb test: Add edge case for writeErrorResponse encode failure
Tests the error logging path when json.Encode fails due to a
write error on the ResponseWriter.
2025-12-01 23:52:21 +00:00
rcourtman
90d81f2217 test: Add edge cases for markAutoRegistered empty inputs
Tests the early return paths when nodeType or nodeName are empty.
2025-12-01 23:50:10 +00:00
rcourtman
3280fad5ae test: Add edge case for clearBootstrapToken remove failure
Tests the warning log path when os.Remove fails with an error other
than ErrNotExist. Uses a directory with contents to trigger ENOTEMPTY.
2025-12-01 23:47:58 +00:00
rcourtman
678c5aac5f test: Add edge cases for initializeBootstrapToken
- Nil router and nil config handling (no panic)
- OIDC enabled clears bootstrap token
Coverage: 80% to 92%.
2025-12-01 23:40:22 +00:00
rcourtman
8c40c7faa3 test: Add panic recovery test for ErrorHandler
Tests that panics in handlers are recovered and return 500.
Coverage: 91.7% to 100%.
2025-12-01 23:37:50 +00:00
rcourtman
d0c2524353 test: Add edge case for handleValidateBootstrapToken invalid JSON
Tests invalid JSON body triggers json.Decode error and returns 400.
Coverage: 90.5% to 100%.
2025-12-01 23:35:40 +00:00
rcourtman
890178acb0 test: Add edge case for RequireScope empty scope
Empty scope should allow all requests through without checking token.
Coverage: 84.6% to 100%.
2025-12-01 23:33:11 +00:00
rcourtman
0fa717a78a test: Add edge case for normalizeNodeHost URL parse error
Control character (null byte) triggers url.Parse error, covering the
'invalid host format' error branch. Coverage: 96.3% to 100%.
2025-12-01 23:28:32 +00:00
rcourtman
08765c7b59 test: Add edge case for DemoModeMiddleware WebSocket POST upgrade
Tests WebSocket upgrade with POST method in demo mode, ensuring the
websocket check branch is exercised after the GET/HEAD/OPTIONS check.
Coverage: 90% to 100%.
2025-12-01 23:24:06 +00:00
rcourtman
a5369ba2cd test: Add test for ErrorHandler empty URL path normalization
Covers the fix for issue #334 where empty path is normalized to '/'.
Coverage: 87.5% to 91.7%.
2025-12-01 23:21:07 +00:00
rcourtman
1fdb15c779 test: Add edge case tests for auth helper functions
- respondMissingScope: nil writer handling (80% to 100%)
- attachAPITokenRecord: nil record handling (80% to 100%)
- getAPITokenRecordFromRequest: wrong type and missing value (87.5% to 100%)
2025-12-01 23:15:04 +00:00
rcourtman
c71fb694bb test: Add edge case test for addQueryParam URL parse error
Add test case for URL containing control character (null byte)
which triggers url.Parse error and returns path unchanged.

Coverage improved from 88.9% to 100%.
2025-12-01 23:08:36 +00:00
rcourtman
37cc97952f test: Add comprehensive test cases for isPrivateIP function
Expand test coverage from 5 cases to 26 cases:
- Public IPv4/IPv6 addresses
- All RFC1918 private ranges (10.x, 172.16-31.x, 192.168.x)
- Loopback addresses (127.x.x.x, ::1)
- Link-local addresses (169.254.x.x, fe80::)
- Link-local multicast (224.0.0.x, ff02::)
- Unique local IPv6 (fc00::/7, fd00::)
- Edge cases: empty string, invalid IP, invalid format
- Addresses with port numbers

Coverage unchanged at 93.8% (remaining 6.2% is defensive
error handling for hardcoded valid CIDRs).
2025-12-01 22:54:56 +00:00
rcourtman
ef380df362 test: Add edge case tests for normalizeNodeHost function
Add 6 new test cases covering previously untested branches:
- Empty host returns error
- Whitespace-only host returns error
- Unknown node type keeps host without port
- Docker node type keeps host without port
- IPv4 address gets default port
- IPv4 with custom port preserved

Coverage improved from 92.6% to 96.3%.
2025-12-01 22:49:29 +00:00
rcourtman
7c27a74c42 test: Add comprehensive tests for PBS snapshot conversion
Add 13 test cases for convertPBSSnapshots covering:
- Empty/nil input handling
- Basic snapshot field mapping
- Files as string array
- Files as object array with filename field
- Invalid file objects ignored gracefully
- Verification status as string ("ok" vs other)
- Verification status as object with state field
- Verification object without state field
- Multiple snapshots with unique IDs
- Empty namespace handling in ID generation
- Container (ct) backup type

Coverage: convertPBSSnapshots 0% -> 100%
2025-12-01 22:23:47 +00:00
rcourtman
4019b3006b test: Add tests for instance lookup and setup token validation
- Add TestFindInstanceNameByHost (12 test cases):
  - PVE instance lookup by host
  - PBS instance lookup by host
  - Unknown node types return empty
  - Empty config handling

- Add TestValidateSetupToken (8 test cases):
  - Empty token returns false
  - Valid/expired/used setup codes
  - Valid/expired recent setup tokens
  - Non-existent token handling
  - Precedence of setup codes over recent tokens

Both functions now have 100% coverage of their logic paths.
2025-12-01 22:19:30 +00:00
rcourtman
b403cdd7b7 test: Add comprehensive tests for convertDockerTasks function
- Test nil input returns nil
- Test empty slice returns nil
- Test single task with all fields populated
- Test task with error state (failed tasks)
- Test multiple tasks conversion
- Test nil time pointers preserved as nil
- Test zero time values converted to nil (defensive handling)
- Test all optional time fields (UpdatedAt, StartedAt, CompletedAt)

Improves monitoring package coverage for Docker Swarm task handling.
2025-12-01 22:13:43 +00:00
rcourtman
67a351fbd9 test: Add tests for webhook template generation and bootstrap token functions
- Add comprehensive tests for generatePayloadFromTemplateWithService covering:
  - Valid JSON template rendering
  - Invalid template syntax error handling
  - Template execution errors
  - ntfy service (plain text, skips JSON validation)
  - Various services (discord, telegram, pagerduty) JSON validation
  - Template function usage (upper, title)
  - Numeric and boolean values in templates
  - Special characters and empty template edge cases

- Add tests for bootstrapTokenValid covering:
  - Nil router handling
  - Empty hash and empty token cases
  - Valid token validation
  - Invalid token rejection
  - Whitespace trimming

- Add tests for clearBootstrapToken covering:
  - Nil router safety
  - Token file deletion
  - Missing file handling
  - Empty path handling
2025-12-01 22:07:40 +00:00
rcourtman
cb683597c6 test: Add tests for GPU temperature parsing functions
- parseGPUTemps: AMD GPU edge/junction/mem temperatures, sensor mapping
- parseNouveauGPUTemps: NVIDIA nouveau GPU core temperature parsing
- Case insensitive sensor name matching
- Invalid/zero/negative temperature handling
- Append behavior for multiple GPUs
2025-12-01 21:56:33 +00:00
rcourtman
3233c48986 test: Add tests for API helper functions
- isRecentlyAutoRegistered: expiry logic, cleanup behavior
- clearAutoRegistered: key deletion, empty input handling
- normalizeDockerAgentArch: all arch variants, case handling, trimming
2025-12-01 21:33:45 +00:00
rcourtman
80702a51bf test: Add tests for prepareWebhookData function
Covers webhook payload data preparation:
- publicURL handling with trailing slash trimming
- alert.Instance URL detection (http/https)
- Metadata extraction and copying
- Value/Threshold rounding to 1 decimal
- AckTime formatting
- CustomFields passthrough
2025-12-01 21:27:29 +00:00
rcourtman
833ec0933f test: Add tests for notification rate limiting and content building
- checkWebhookRateLimit: rate limit window, counter, per-URL isolation
- buildResolvedNotificationContent: single/multiple alerts, nil filtering,
  HTML escaping, timestamp handling, optional fields
2025-12-01 21:25:02 +00:00
rcourtman
334cffb1c7 test: Add tests for monitor helper and metrics functions
- clearGuestMetadataCache: nil safety, cache clearing, key isolation
- shouldRunBackupPoll: interval-based, cycle-based, config validation
- storeNodeLastSuccess/lastNodeSuccessFor: store/retrieve, overwrite, missing keys

Improves coverage for backup polling logic and node metrics tracking.
2025-12-01 21:18:33 +00:00
rcourtman
8198e1d839 test: Add comprehensive tests for guest metadata functions
Tests for rate limiting, retry, and slot management:
- retryGuestAgentCall: timeout retry, non-timeout break, context cancellation
- acquireGuestMetadataSlot: nil safety, slot acquisition, context cancellation
- releaseGuestMetadataSlot: nil safety, non-blocking release
- tryReserveGuestMetadataFetch: reservation logic, default hold duration
- scheduleNextGuestMetadataFetch: interval, jitter, RNG handling
- deferGuestMetadataRetry: backoff logic, defaults

Covers error handling and edge cases in guest agent metadata fetching.
2025-12-01 21:10:28 +00:00
rcourtman
a3eb81778f test: Add table-driven tests for parseSensorsJSON
Comprehensive coverage for temperature sensor JSON parsing:
- Empty/whitespace input handling
- Invalid JSON error handling
- Legacy and wrapper format support
- Multiple chip types: coretemp, k10temp, acpitz, nvme, amdgpu, nouveau, zenpower, nct6795, it87, rp1_adc
- Edge cases: non-map chip data, CPUMax calculation from cores
2025-12-01 21:00:46 +00:00
rcourtman
1af38e3f99 test: Add tests for parseContainerMountMetadata, convertContainerDiskInfo, StalenessScore
- parseContainerMountMetadata: parts without equals, mountpoint key variant,
  whitespace handling, single source value (96.4% -> 100%)
- convertContainerDiskInfo: nil metadata, device from metadata, negative free
  clamping, whitespace label handling (95.1% -> 97.6%, remaining is dead code)
- StalenessScore: negative maxStale default, metrics lookup failure, score
  clamping edge cases (95.7% - remaining is defensive dead code)
2025-12-01 20:44:00 +00:00
rcourtman
ed0644035f test: Add tests for sanitizeGuestAddressStrings, parseContainerConfigNetworks, mergeNVMeTempsIntoDisks
- sanitizeGuestAddressStrings: IPv6 loopback with CIDR (::1/128) edge case
  (96.2% -> 100%)
- parseContainerConfigNetworks: parts without equals, mac/ips/ip6addr/ip6prefix
  key variants, whitespace-only values, all-empty results (97.2% -> 100%)
- mergeNVMeTempsIntoDisks: NVMe disk with no legacy temps (continue branch),
  more disks than temps (break branch) (97% -> 100%)
2025-12-01 20:34:48 +00:00
rcourtman
4e33b396e0 test: Add tests for normalizeEndpointHost, SelectInterval, generateDockerHostIdentifier
- normalizeEndpointHost: port-only URL host (parsed.Host fallback),
  edge cases for URL parsing (94.4% -> 100%)
- SelectInterval: negative penalty, instance key derivation, clamping
  edge cases (96% - remaining is unreachable dead code guards)
- generateDockerHostIdentifier: empty base fallbacks, suffix candidates,
  hash suffix, numeric suffix increments (91.7% -> 100%)
2025-12-01 20:26:21 +00:00
rcourtman
4c91dce2f8 test: Add tests for allow, ensureContainerRootDiskEntry; remove dead code
- allow (circuitBreaker): all states including unknown/default branch,
  open→half-open transition, half-open window timing (93.8% -> 100%)
- ensureContainerRootDiskEntry: nil container, existing disks, used>total
  clamping, negative free clamping, usage calculation (92.3% -> 100%)
- convertPoolInfoToModel: removed unreachable nil check (dead code since
  ConvertToModelZFSPool only returns nil for nil receiver) (88.9% -> 100%)
2025-12-01 20:15:32 +00:00
rcourtman
0a9177f161 test: Add tests for lookupClusterEndpointLabel, GetNodeMetrics, stateDetails
- lookupClusterEndpointLabel: nil instance, no match, Host vs IP fallback,
  case-insensitive NodeName, whitespace handling (84.6% -> 100%)
- GetNodeMetrics: unknown metric types, empty nodeID, zero duration,
  empty metrics data, disk type (94.1% -> 100%)
- stateDetails: all breaker states including unknown/invalid state,
  retryAt calculations, timestamps (90% -> 100%)
2025-12-01 20:07:22 +00:00
rcourtman
2fdc051c11 fix: Make parseNVMeTemps deterministic by checking Composite before Sensor 1
Go map iteration order is non-deterministic, causing flaky test failures.
This fix ensures "Composite" sensor is always preferred over "Sensor 1"
by checking them in separate loops rather than relying on iteration order.
2025-12-01 20:03:05 +00:00
rcourtman
f79d20296b test: Add tests for GetGuestMetrics, mergeSnapshot, getDockerCommandPayload
- GetGuestMetrics: all metric types, duration filtering, guest not found,
  unknown metric type, empty data (81% -> 100%)
- mergeSnapshot: timestamp merging for LastSuccess/LastError/LastMutated,
  ChangeHash preservation (86.7% -> 100%)
- getDockerCommandPayload: empty hostID, whitespace normalization, host
  not found, expired command cleanup, queued->dispatched marking,
  already-dispatched preservation (91.3% -> 100%)
2025-12-01 19:58:43 +00:00
rcourtman
196389853e test: Add tests for StalenessScore, parseCPUTemps, queueDockerStopCommand
- StalenessScore: 78.3%→95.7% (4 cases for metrics, future timestamp, defaults)
- parseCPUTemps: 98.1%→100% (core temp exceeding package case)
- queueDockerStopCommand: 76.9%→100% (12 cases for validation, status checks)
2025-12-01 19:50:42 +00:00
rcourtman
2594a6c124 test: Add tests for handleProxyHostFailure, recordNodeSnapshot, evaluateHostAgents
- handleProxyHostFailure: 76.5%→100% (9 cases for per-host failure tracking)
- recordNodeSnapshot: 75%→100% (6 cases for diagnostic snapshot storage)
- evaluateHostAgents: 87%→100% (10 cases for host health evaluation)
2025-12-01 19:40:32 +00:00
rcourtman
c6a34c4412 test: Add tests for handleProxyFailure, parseRPiTemperature, RecordResult
- handleProxyFailure: 86.7%→100% (6 cases for proxy disable threshold logic)
- parseRPiTemperature: 77.8%→100% (7 cases for RPi temp parsing edge cases)
- RecordResult: 95.8%→100% (negative staleness clamping case)
2025-12-01 19:33:06 +00:00
rcourtman
1f380eaaf3 test: Add tests for isProxyEnabled, taskHeap.Pop, NewAdaptiveScheduler
- isProxyEnabled: 94.4%→100% (7 cases for proxy cooldown/restore logic)
- taskHeap.Pop: 87.5%→100% (3 cases for empty/single/multi-element heap)
- NewAdaptiveScheduler: 84.6%→100% (14 cases for default value handling)
2025-12-01 19:26:37 +00:00
rcourtman
0ed84f3179 test: Add tests for disableLegacySSHOnAuthFailure, parseNVMeTemps, updateDeadLetterMetrics
- disableLegacySSHOnAuthFailure: 87.5%→100% (13 cases for auth error detection)
- parseNVMeTemps: 88.9%→100% (16 cases for NVMe temp parsing)
- updateDeadLetterMetrics: 75%→100% (6 cases for nil handling, queue states)
2025-12-01 19:20:09 +00:00
rcourtman
7bab2f86af test: Add tests for AllowDockerHostReenroll, SelectInterval, ensureBreaker
- AllowDockerHostReenroll: 95%→100% (7 cases for empty/blocked/cleanup paths)
- ensureBreaker: 94.4%→100% (6 cases for nil map, existing, custom config)
- SelectInterval: 94%→96% (20+ cases for edge cases, remaining guards unreachable)
2025-12-01 19:13:40 +00:00
rcourtman
e7bc06033a test: Add tests for convertDockerSwarmInfo, namespacePathsForDatastore, preserveFailedStorageBackups
- convertDockerSwarmInfo: 66.7%→100% (4 cases for nil, empty, populated structs)
- namespacePathsForDatastore: 92.3%→100% (removed unreachable dead code)
- preserveFailedStorageBackups: 91.3%→100% (6 cases for filtering, deduplication)
2025-12-01 19:04:23 +00:00
rcourtman
0bfc9ed447 test: Add tests for storageNamesForNode, GetDockerHost, and SchedulerHealth edge cases
- storageNamesForNode: 83.3%→100% (8 cases for filtering logic)
- GetDockerHost: 75%→100% (5 cases for lookup and whitespace handling)
- SchedulerHealth: 85.3%→89.1% (13 cases for nil handling, breaker key parsing)
2025-12-01 18:57:09 +00:00
rcourtman
2d775e9409 test: Add tests for polling interval, proxy success handlers, and failed instance removal
- effectivePVEPollingInterval: 80%→100% (6 cases for nil/clamping)
- handleProxySuccess: 80%→100% (3 cases for nil client, reset)
- handleProxyHostSuccess: →100% (6 cases for empty/whitespace/removal)
- removeFailedPBSNode: 75%→100% (5 cases for removal, backups, health)
- removeFailedPMGInstance: 75%→100% (5 cases for removal, backups, health)
2025-12-01 18:49:09 +00:00
rcourtman
acb7f4cf3a test: Add tests for normalizeEndpointHost, taskExecutionTimeout, decrementPending
- normalizeEndpointHost: 89%→94.4% (19 cases covering schemes, ports, paths, edge cases)
- taskExecutionTimeout: 83%→100% (4 cases covering defaults and custom timeouts)
- decrementPending: 88%→100% (5 cases covering decrement logic and no-op scenarios)
2025-12-01 18:42:57 +00:00
rcourtman
6183727368 test: Add tests for getNodeDisplayName, lookupClusterEndpointLabel, extractSnapshotName
- getNodeDisplayName: 71%→100% (12 tests covering cluster/non-cluster fallbacks)
- lookupClusterEndpointLabel: 77%→85% (14 tests covering endpoint matching)
- extractSnapshotName: 78%→100% (8 tests covering volid parsing)

Monitoring package 46.2%→46.4%
2025-12-01 18:37:27 +00:00
rcourtman
330cec7829 test: Add tests for clampUint64ToInt64 and resetAuthFailures
- clampUint64ToInt64: 67%→100% (5 tests covering boundary conditions)
- resetAuthFailures: 67%→100% (6 tests covering map cleanup logic)

Note: cloneStringFloatMap and cloneStringMap tests already existed.
2025-12-01 18:31:34 +00:00
rcourtman
7672cad174 test: Add tests for SetBreakerState, RecordResult, ResetQueueDepth, IncInFlight, DecInFlight
- SetBreakerState: 67%→100% (8 tests covering state conversion, retryAt clamping)
- RecordResult: 75%→96% (11 tests covering success/failure paths, staleness)
- ResetQueueDepth: 75%→100% (4 tests covering negative clamping)
- IncInFlight/DecInFlight: 67%→100% (4 tests)

Monitoring package 45.9%→46.2%
2025-12-01 18:27:05 +00:00
rcourtman
44b6745741 test: Add tests for recordAuthFailure, shouldSkipProxyHost, recoverFromPanic
- recordAuthFailure: 53%→100% (8 tests covering failure counting, node removal)
- shouldSkipProxyHost: 44%→100% (9 tests covering cooldown logic, state cleanup)
- recoverFromPanic: 50%→100% (7 tests covering various panic value types)

Monitoring package 45.3%→45.9%
2025-12-01 18:20:12 +00:00
rcourtman
b4fb5d2a6a test: Add tests for mergeNVMeTempsIntoDisks, UpdateQueueSnapshot, UpdateDeadLetterCounts, templateFuncMap
- mergeNVMeTempsIntoDisks: 57%→97% (14 tests covering WWN/serial/path matching, NVMe fallback)
- UpdateQueueSnapshot: 57%→100% (5 tests covering nil, gauges, stale key cleanup)
- UpdateDeadLetterCounts: 52%→100% (7 tests covering aggregation, normalization)
- templateFuncMap: 20%→100% (8 tests covering all template helper functions)

Monitoring 44.6%→45.3%, notifications 45.7%→45.9%
2025-12-01 18:14:43 +00:00
rcourtman
0803951854 test: Add tests for getInstanceConfig, baseIntervalForInstanceType, LoadOIDCConfig
- getInstanceConfig: 33%→100% (nil handling, case-insensitive matching)
- baseIntervalForInstanceType: 50%→100% (all instance types, clamping)
- LoadOIDCConfig: 35%→94% (file not exist, read errors, decryption)
2025-12-01 18:06:15 +00:00
rcourtman
4defced1a6 test: Add monitoring tests for parseDurationEnv, parseIntEnv, markFailed, logNodeMemorySource
Add comprehensive test coverage for:
- parseDurationEnv: empty/unset env, valid durations, invalid inputs
- parseIntEnv: empty/unset env, valid integers, invalid inputs
- markFailed: status setting, timestamps, failure reason
- logNodeMemorySource: nil handling, source change detection, log levels

All four functions now at 100% coverage (up from 0-78%).
2025-12-01 17:59:20 +00:00
rcourtman
7314510280 test: Add tests for SSH knownhosts error and path methods
- HostKeyChangeError.Error(): message formatting
- HostKeyChangeError.Unwrap(): error chain verification
- manager.Path(): path retrieval
- HostFieldMatches(): host matching patterns

ssh/knownhosts coverage: 72.2% → 75.0%
2025-12-01 17:50:13 +00:00
rcourtman
5d592bf4e6 test: Add tests for diagnostic snapshot recording and retrieval
- recordGuestSnapshot: nil handling, field setting, map initialization
- GetDiagnosticSnapshots: nil/empty handling, sorting verification

Both functions now at 100% coverage.
2025-12-01 17:48:36 +00:00
rcourtman
3de1eafd65 test: Add error path tests for config persistence functions
- LoadAPITokens: invalid JSON, empty file, file not exist
- LoadEmailConfig: invalid JSON, file not exist
- LoadWebhooks: invalid JSON, legacy migration
- LoadNodesConfig: empty arrays, missing fields, corruption recovery
- cleanupOldBackups: non-existent dir, multiple files cleanup
- Bonus: LoadAppriseConfig, LoadAlertConfig, LoadSystemSettings error paths

config package coverage: 46.3% → 48.2%
2025-12-01 17:45:50 +00:00
rcourtman
2158c14cce test: Add comprehensive tests for API token management
- Clone: deep copy verification for pointers and slices
- NewAPITokenRecord/NewHashedAPITokenRecord: creation and validation
- Config methods: HasAPITokens, APITokenCount, ActiveAPITokenHashes
- Config methods: HasAPITokenHash, PrimaryAPITokenHash, PrimaryAPITokenHint
- Config methods: ValidateAPIToken, UpsertAPIToken, RemoveAPIToken, SortAPITokens

config package coverage: 43.5% → 46.3%
2025-12-01 17:37:27 +00:00
rcourtman
d6359276ed test: Add tests for monitoring and notifications functions
- buildCephClusterModel: 0% → 100% (11 test cases)
- collectContainerRootUsage: 0% → 100% (18 test cases)
- NotificationManager getters/setters: 8 functions now tested

Overall coverage: 45.5% → 45.8%
2025-12-01 17:33:36 +00:00
rcourtman
caa33b3140 test: Add tests for checkPMGNodeQueues
- 12 test cases covering per-node queue monitoring
- Tests total/deferred/hold queue thresholds at warning/critical levels
- Tests oldest message age per node
- Tests outlier detection, threshold clearing, existing alert updates
- Tests empty nodes and nil QueueStatus handling

Coverage: checkPMGNodeQueues 0%→85.1%
Package coverage: 70.3%→72.3%
2025-12-01 17:16:32 +00:00
rcourtman
5f85f4e5ac test: Add tests for checkZFSPoolHealth
- 14 test cases covering pool state alerts (ONLINE, DEGRADED, FAULTED,
  UNAVAIL), pool error tracking, device-level alerts, state transitions
- Tests pool state clearing on recovery, error count updates,
  SPARE device handling, FAULTED device critical alerts

Coverage: checkZFSPoolHealth 0%→100%
Package coverage: 68.6%→70.3%
2025-12-01 17:14:12 +00:00
rcourtman
e3b8a00fe4 test: Add tests for checkEscalations and CleanupAlertsForNodes
- checkEscalations: 6 test cases covering disabled/enabled states,
  acknowledged alerts, threshold timing, multi-level escalation
- CleanupAlertsForNodes: 7 test cases covering node removal,
  Docker/PBS alert preservation, empty node handling, nil safety

Coverage: checkEscalations 0%→100%, CleanupAlertsForNodes 0%→92%
Package coverage: 67.6%→68.6%
2025-12-01 17:11:47 +00:00
rcourtman
1aa5eeb0cb test: Add tests for Cleanup and convertLegacyThreshold
- Cleanup: 16 test cases covering auto-acknowledge, TTL cleanup,
  rate limit entries, suppressions, pending alerts, flapping history,
  Docker restart tracking, PMG anomaly trackers, quarantine history
- convertLegacyThreshold: 5 test cases covering nil/zero/negative input,
  default margin, custom margin

Coverage: Cleanup 0%→97.6%, convertLegacyThreshold 0%→83.3%
Package coverage: 65.4%→67.6%
2025-12-01 17:08:45 +00:00
rcourtman
24c44c8e5a test: Add tests for checkStorageOffline and checkGuestPoweredOff
- checkStorageOffline: 5 test cases covering confirmation polling,
  alert creation, LastSeen updates, disabled storage handling
- checkGuestPoweredOff: 9 test cases covering confirmation polling,
  alert creation, severity overrides, disabled guests, monitorOnly flag

Coverage: checkStorageOffline 0%→100%, checkGuestPoweredOff 0%→100%
Package coverage: 63.4%→65.4%

Note: Pre-existing test failure in suite related to /etc/pulse file
access - not caused by these changes.
2025-12-01 17:05:15 +00:00
rcourtman
6806512ef1 test: Add tests for checkPMGQueueDepths and checkPMGOldestMessage
- checkPMGQueueDepths: 10 test cases covering total/deferred/hold queues
  at warning/critical levels, existing alert updates, threshold clearing
- checkPMGOldestMessage: 8 test cases covering threshold logic,
  multi-node oldest detection, alert creation/updates/clearing

Coverage: checkPMGQueueDepths 0%→88.1%, checkPMGOldestMessage 0%→100%
Package coverage: 61.3%→63.4%
2025-12-01 16:59:59 +00:00
rcourtman
b7c08ca6e1 test: Add tests for calculateTrimmedBaseline and createOrUpdateNodeAlert
- calculateTrimmedBaseline: 8 test cases covering sample count thresholds,
  trimmed mean calculation, median fallback logic, odd-length arrays
- createOrUpdateNodeAlert: 2 test cases for new alert creation and
  existing alert updates

Coverage: calculateTrimmedBaseline 0%→96.9%, createOrUpdateNodeAlert 0%→100%
Package coverage: 59.6%→61.3%
2025-12-01 16:56:14 +00:00
rcourtman
34b4a0d50c test: Add tests for checkPBSOffline and checkPMGOffline functions
checkPBSOffline (0%→100%):
- Override Disabled clears alert and returns
- Override DisableConnectivity clears alert and returns
- Insufficient confirmations waits
- Creates alert after 3 confirmations
- Existing alert updates LastSeen

checkPMGOffline (0%→100%):
- Override Disabled clears alert and returns
- Override DisableConnectivity clears alert and returns
- Insufficient confirmations waits
- Creates alert after 3 confirmations
- Existing alert updates LastSeen

Coverage: 58.6% → 59.6%
2025-12-01 16:50:18 +00:00
rcourtman
42ded0dd23 test: Add tests for checkNodeOffline function
checkNodeOffline (0%→100%):
- Override DisableConnectivity clears alert and returns
- Existing alert updates StartTime
- Insufficient confirmations waits (1, 2 confirmations)
- Creates alert after 3 confirmations with correct metadata
- Alert added to history

Coverage: 58.5% → 58.6%
2025-12-01 16:48:13 +00:00
rcourtman
785a03ea77 test: Add tests for offline alert clearing functions
clearNodeOfflineAlert (0%→100%):
- No alert and no count is no-op
- Resets offline count when node comes online
- Clears existing alert and adds to resolved

clearPBSOfflineAlert (0%→100%):
- No alert and no count is no-op
- Resets offline confirmation count
- Clears existing alert and adds to resolved

clearPMGOfflineAlert (0%→100%):
- No alert and no count is no-op
- Resets offline confirmation count
- Clears existing alert and adds to resolved

Coverage: 57.4% → 58.5%
2025-12-01 16:45:51 +00:00
rcourtman
b9e49a26c4 test: Add tests for alert utility functions
SetMetricHooks (0%→100%):
- Sets all four hooks correctly
- Nil hooks are safely handled
- Properly saves/restores state to avoid test pollution

NotifyExistingAlert (0%→100%):
- Non-existent alert is no-op
- Existing alert dispatches async notification

GetResolvedAlert (0%→100%):
- Returns nil for non-existent alert
- Returns nil for nil resolved entry
- Returns nil when Alert is nil
- Returns cloned alert with resolved time

GetAlertHistory/GetAlertHistorySince (0%→100%):
- Returns history from history manager
- Respects limit parameter
- Zero time returns all history
- Filters by time correctly

ClearAlertHistory (0%→100%):
- Clears all history entries

Coverage: 56.9% → 57.4%
2025-12-01 16:43:04 +00:00
rcourtman
5c584b9eee test: Add comprehensive tests for HandleDockerHostOffline
HandleDockerHostOffline (0%→100%):
- Empty host ID is no-op
- Disabled alerts is no-op
- DisableAllDockerHostsOffline clears tracking and alert
- Override DisableConnectivity clears tracking and alert
- Existing alert updates LastSeen
- Requires 3 confirmations before alert
- Alert has correct metadata (resourceType, hostId, agentId)

Coverage: 55.6% → 56.9%
2025-12-01 16:39:10 +00:00
rcourtman
7bac96d60b test: Add comprehensive tests for HandleHostRemoved, ReevaluateGuestAlert
HandleHostRemoved (0%→100%):
- Empty host ID is no-op
- Clears host offline alert and confirmations
- Clears host metric alerts (CPU, memory)
- Clears host disk alerts
- Clears all alert types together

ReevaluateGuestAlert (0%→100%):
- No active alerts is no-op
- Clears alert when threshold disabled (nil)
- Clears alert when trigger is zero
- Clears alert when value below clear threshold
- Clears alert when value below trigger threshold
- Keeps alert when value above both thresholds
- Processes all metric types (7 types)
- Clears pending alert when threshold disabled
- Uses clear equals trigger when clear is zero
- Ignores alerts for different guests

NormalizeMetricTimeThresholds (0%→100%):
- Updated existing test to call public wrapper instead of internal function

Coverage: 54.6% → 55.6%
2025-12-01 16:36:48 +00:00