- calls callback synchronously with alert ID
- calls callback asynchronously
- noop when callback is nil
- recovers from panic in sync and async callbacks
- safeCallResolvedCallback 90%→100%
- calls callback with alert and level
- noop when callback is nil
- recovers from panic in callback
- clones alert to prevent concurrent modification
- safeCallEscalateCallback 0%→100%
- clears alerts and state tracking not in seen set
- skips alerts from other hosts
- handles empty seen set (clears all)
- cleanupDockerContainerAlerts 75%→100%
- clears alerts not in seen set (stale disk alerts)
- empty host ID is noop
- skips nil alerts without panic
- skips non-matching prefix (non-disk alerts)
- cleanupHostDiskAlerts 76.9%→100%
- clears all disk alerts for specified host
- empty hostID is noop
- skips nil alerts without panic
- noop when no matching alerts
- clearHostDiskAlerts 72.7%→100%
- with/without host ID (prefix selection)
- derives ID from service name with sanitization
- special chars replaced with dashes
- preserves alphanumeric, underscore, hyphen
- trims leading/trailing dashes/underscores
- truncates long IDs to 32 chars
- fallback to 'service' when empty
- dockerServiceResourceID 23.8%→100%
- returns name when present
- returns trimmed name
- returns truncated ID when name empty (first 12 chars)
- returns full short ID when < 12 chars
- returns 'service' when both empty/whitespace
- prefers name over ID
- dockerServiceDisplayName 33.3%→100%
- nil thresholds get defaults (CPU 95, Memory 92, Disk 95)
- low thresholds raised to minimum relaxed values
- high thresholds unchanged
- clear adjusted when too close to trigger
- original config unchanged (no mutation)
- alerts package coverage improvement: applyRelaxedGuestThresholds 75%→93.8%
Cover all branches: disabled rate limit (zero/negative MaxAlertsHour),
under limit, at limit blocking, separate limits per alertID, old entry
cleanup, and mixed old/recent entries. Coverage improved from 71.4% to 100%.
Cover both branches: single alert template (isSingle=true with 1 alert)
and grouped alert template (isSingle=false or multiple alerts). Tests
verify subject format, HTML structure, and text body generation.
Coverage improved from 66.7% to 100%.
Cover all branches: nil/empty TimeThresholds, direct match, canonical key
matching (vm→guest, container→guest), "all" fallback, specific match
precedence, and global threshold fallback. Coverage improved from 85.7% to 100%.
Cover all branches: user without realm gets @pam appended, user with
realm unchanged, token auth skips user modification, empty user handling,
and fingerprint/verifySSL preservation. Coverage improved from 66.7% to 100%.
Cover all branches: disabled state, invalid timezone fallback, day not
enabled, invalid start/end time parsing, overnight window spanning
midnight, and normal daytime window. Coverage improved from 61.5% to 96.2%.
Cover all branches of flapping detection: disabled state, below/at/above
threshold, already-flapping state (no suppression update), and window
expiry pruning. Coverage improved from 61.9% to 95.2%.
- Test different instance and node (full format)
- Test same instance and node (short format)
- Test empty instance defaults to node
- Test whitespace trimming
- Improves BuildGuestKey coverage from 71.4% to 100%
Add test case for malformed IPv6 URL that triggers url.Parse error.
Improves coverage from 90% to 95%. The remaining 5% is a template
Execute error path that's effectively unreachable with current types.
When tasks have identical NextRun and Priority, the Less function
falls back to comparing InstanceName alphabetically. Add test to
cover this edge case branch, improving Less coverage to 100%.
Tests for alert filter evaluation logic:
- evaluateVMCondition: metric/text/raw conditions for VMs
- evaluateContainerCondition: same for containers
- evaluateFilterStack: AND/OR logic with multiple conditions
- evaluateFilterCondition: type dispatch
74 test cases covering:
- All metric types (cpu, memory, disk, diskread, diskwrite, network)
- All comparison operators (>, <, >=, <=, =, ==)
- Text search fields (name, node, vmid) with case insensitivity
- Raw text search across multiple fields
- Value type conversions (int to float64)
- Edge cases (zero, empty, invalid types)
Coverage improved from 46.8% to 48.9%.
Tests for LXC container config parsing functions:
- sanitizeRootFSDevice: rootfs device extraction
- collectIPsFromInterface: recursive IP extraction from various types
- parseContainerRawIPs: JSON IP parsing
- parseContainerConfigNetworks: network interface parsing with MAC
normalization, CIDR stripping, sorting
- parseContainerMountMetadata: mount point metadata parsing
- extractContainerRootDeviceFromConfig: root device extraction
- mergeContainerNetworkInterface: interface merging by name/MAC
- convertContainerDiskInfo: Proxmox disk info conversion
- ensureContainerRootDiskEntry: root disk entry creation
91+ test cases covering edge cases, invalid data, and complex scenarios.
Coverage improved from 40.6% to 42.2%.
Tests for all 9 functions handling Docker host identification:
- uniqueNonEmptyStrings: dedupe with order preservation
- sanitizeDockerHostSuffix: string cleaning for IDs
- tokenHintFromRecord: redacted token hints
- dockerHostIDExists: ID existence check
- dockerHostSuffixCandidates: candidate suffix generation
- fallbackDockerHostID: hash-based ID generation
- findMatchingDockerHost: host matching by various criteria
- generateDockerHostIdentifier: unique ID generation with suffixes
- resolveDockerHostIdentifier: main resolver orchestration
86 test cases covering edge cases (nil, empty, whitespace), Unicode
handling, and complex matching scenarios.
Tests cover nil/empty inputs, basic field copying, time fields
(CreatedAt/UpdatedAt with nil and zero value handling), update status
conversion, endpoint ports, and labels cloning.
Add comprehensive error handling tests for two pure functions:
renderWebhookURL (8 new test cases):
- Empty/whitespace URL template validation
- Invalid template syntax (unclosed braces, undefined functions)
- Template producing empty URL
- Missing scheme or host in rendered URL
UpdateAllowedPrivateCIDRs (expanded from 8 to 29 cases):
- Invalid IP addresses (garbage, out of range, malformed)
- Invalid CIDR notation (prefix too large, negative, non-numeric)
- Malformed strings (double slash, invalid IP with valid prefix)
- Success cases for valid IPv4/IPv6 CIDRs and bare IPs
- Use public API AcknowledgeDockerHostCommand instead of private function
- Use strings.Contains instead of custom helper functions
- Add test case for empty hostID (skips validation, succeeds)
The error message referenced "Settings -> Docker -> Removed hosts" but
that UI path no longer exists. The correct path is now
"Settings -> Agents -> Removed Docker Hosts".
Related to #778
Add comprehensive tests for EnhancedEmailManager covering:
- Rate limiting (exceeds limit, resets after minute, concurrency, negative values)
- Provider username defaults (SendGrid, SparkPost, Resend, Postmark)
- TLS routing (TLS, StartTLS, plain connections)
- Retry logic (retries on failure, rate limit prevents retry)
- Connection error handling for sendTLS, sendStartTLS, sendPlain
This is the first test file for email_enhanced.go which previously had
0% coverage on sendTLS, sendStartTLS, and TestConnection functions.
Move guest threshold resolution and filter evaluation logic from
alerts.go to filter_evaluation.go for better code organization.
Extracted functions:
- evaluateFilterCondition
- evaluateVMCondition
- evaluateContainerCondition
- evaluateFilterStack
- getGuestThresholds
This reduces alerts.go by ~370 lines and isolates the rule evaluation
engine that determines which thresholds apply to guests.
Cover API validation functions that were previously untested:
- validateIPAddress: IPv4/IPv6 validation with edge cases
- validatePort: Port range validation (1-65535)
- defaultPortForNodeType: Proxmox node type to default port mapping
This function was superseded by HandleTestNode which is wired to the
router at /api/config/nodes/{id}/test. The old function was not
registered in the router and served no purpose.
Removes 121 lines of unused code.
The host-agent's isCPUChip function was missing rp1_adc (Raspberry Pi RP1 ADC),
which is already detected in the monitoring package. This sync ensures consistent
CPU temperature chip detection across both code paths.
Tests for annotateResolvedMetadata, resolveAppriseNotificationType,
normalizeQueueType, and resolvedTimeFromAlerts (44 test cases).
Coverage 38.0% → 39.0%.
Add 56 test cases covering:
- isTransientError: 13 cases for context errors, retryable MonitorErrors,
and standard error types (nil, Canceled, DeadlineExceeded, Timeout, etc.)
- shouldTryPortlessFallback: 14 cases for connection error patterns that
trigger port fallback (refused, reset, no such host, timeout variants)
- shouldAttemptFallback: 13 cases for timeout/deadline/canceled patterns
used in storage polling fallback
- classifyDLQReason: 8 cases for dead letter queue reason classification
(max_retry_attempts vs permanent_failure)
- Edge cases: 3 cases for overlapping error patterns and partial matches
First test file for these error classification utilities used in retry
and fallback decision logic.
52 test cases covering:
- firstValueForKeys: 18 cases for multi-key lookup with priority ordering
- hasAnyKey: 15 cases for key existence checking
- discoveryConfigMap: 19 cases for nested config extraction with camelCase/snake_case support
Tests verify edge cases including nil maps, empty key slices, type assertion failures,
and priority ordering for field name variants used in configuration parsing.
Add 97 test cases for four utility functions in monitor.go:
- stringValue (30 cases): Type-to-string conversion for various Go types
including string, int types, float types, json.Number, fmt.Stringer
- anyToInt64 (34 cases): Interface-to-int64 conversion with overflow
handling, string parsing, and json.Number support
- parseInterfaceStat (15 cases): Interface stat map parsing for network
interface statistics
- extractGuestOSInfo (18 cases): QEMU guest agent OS info extraction
with fallback logic for various Linux distros, Windows, FreeBSD
Coverage for these functions: 0% → 100%
Package coverage: 37.5% → 38.5%
Added comprehensive tests for 6 previously untested pure utility functions:
- sortContent: sorts comma-separated storage content values
- formatSeconds: converts total seconds to HH:MM:SS format
- dedupeStringsPreserveOrder: deduplicates strings while preserving order
- sanitizeGuestAddressStrings: validates and filters IP addresses
- copyFloatPointer: creates independent copy of float64 pointer
- clampInterval: clamps time.Duration to specified bounds
Tests cover edge cases including empty inputs, boundary conditions,
special values (DHCP, loopback addresses), and various separators.
Coverage increased from 36.8% to 37.5%.
Coverage for sessionHash, CreateSession, ValidateSession,
ValidateAndExtendSession, DeleteSession, persistence, and cleanup.
21 test cases covering session lifecycle, expiration handling,
and disk persistence. Coverage 25.0% → 25.3%.
Tests for detectProxy, isConnectionSecure, getCookieSettings, and
generateSessionToken functions. Covers proxy detection for various
headers including X-Forwarded-For, CF-Ray, Forwarded (RFC 7239),
and secure connection detection via TLS and proxy headers.
32 test cases covering makeNodeSnapshotKey and makeGuestSnapshotKey
utility functions used for diagnostic memory snapshot storage. Tests
cover simple inputs, edge cases (empty strings, negative VMIDs),
special characters, and key uniqueness verification. Also includes
struct field tests for NodeMemoryRaw and VMMemoryRaw.
First test file for diagnostic_snapshots.go. Coverage 36.7% → 36.8%.
The backup status indicator feature was incomplete - it added the UI
component but never populated VM/Container LastBackup from actual
backup data. Now SyncGuestBackupTimes() is called after storage
backups and PBS backups are polled, matching each guest's VMID to
its most recent backup timestamp.
Fixes#786
24 test cases covering transaction lifecycle: staging, commit, rollback, and cleanup.
Tests include atomic commit behavior, backup/restore on failure, directory creation,
permission handling, and idempotent cleanup.
First test file for import_transaction.go. Coverage 42.4% → 42.7%.
22 test cases covering CRUD operations (Get, GetAll, Set, Delete,
ReplaceAll), persistence (Load, save with atomic write, directory
creation), legacy ID migration (GetWithLegacyMigration for clustered
and standalone formats), round-trip verification, and concurrency.
First test file for guest_metadata.go, complementing the similar
docker_metadata_test.go added in previous run.
When multiple cluster nodes register sensor-proxy, each registration
was overwriting the previous node's control token on the shared
PVEInstance. This caused "Proxy token not recognized" errors on all
but the last-registered node.
Changes:
- Add TemperatureProxyControlToken field to ClusterEndpoint struct
- Store control tokens per-endpoint for cluster registrations
- Check both instance-level and endpoint-level tokens when validating
Related to #738
Test coverage for internal/config/oidc.go functions:
- normaliseList: 8 cases for deduplication, trimming, empty handling
- parseDelimited: 8 cases for comma/space separation
- DefaultRedirectURL: 7 cases for URL construction
- OIDCConfig.Clone: 2 cases for deep copy behavior
- OIDCConfig.ApplyDefaults: 9 cases for defaults and normalization
- OIDCConfig.Validate: 9 cases for validation rules
- OIDCConfig.MergeFromEnv: 5 cases for environment variable merging
- NewOIDCConfig: constructor verification
Total: 56 new test cases (583 lines).
Tests for unified_agent.go:
- normalizeUnifiedAgentArch: 51 test cases covering all supported
architectures (linux/darwin/windows), case insensitivity,
whitespace handling, and invalid inputs
Tests for updates.go:
- getClientIP: 18 test cases covering X-Forwarded-For priority,
X-Real-IP fallback, RemoteAddr extraction, IPv4/IPv6 support,
nil header safety, and case insensitivity
Tests for the responseWriter struct in middleware.go:
- APIError.Error() interface implementation (3 cases)
- WriteHeader once-only semantics (4 cases)
- Write with implicit WriteHeader (3 cases)
- StatusCode nil safety (4 cases)
- Hijack support detection (2 cases)
- Flush support detection (3 cases)
- Full flow integration and edge cases (4 cases)
First test file for middleware.go. 22 test cases total covering
HTTP response wrapper behavior used by ErrorHandler middleware.
- extractHostPart: 22 test cases covering URL parsing, hostname extraction
- buildAuthorizedNodeList: 8 test cases for PVE instance node list building
- generateSecureToken: 5 test cases for cryptographic token generation
- proxySyncState: 6 test cases for sync status tracking and snapshots
First test file for temperature_proxy.go utility functions.
Added 17 new test functions covering:
- DockerHost.ToFrontend() with variants for empty display name, swarm,
services, tasks, and command status
- Host.ToFrontend() with display name fallback logic
- CephCluster.ToFrontend() including empty pools/services case
- ReplicationJob.ToFrontend() including nil time handling
- DockerServiceUpdate.ToFrontend()
- DockerContainer.ToFrontend() for Podman info
Coverage improved from 33.0% to 44.0% in internal/models package.
syscall.Exec is not supported on Windows, causing self-update to fail
with "failed to restart: not supported by windows".
Split restart logic into platform-specific files:
- restart_unix.go: Uses syscall.Exec for in-place process replacement
- restart_windows.go: Uses os.Exit(0) to let Windows SCM restart service
Related to #735
Test coverage for isMonitorOnlyAlert, quietHoursCategoryForAlert, and
ensureValidHysteresis functions that were previously untested. Improves
internal/alerts coverage from 46.4% to 46.8%.