mirror of
https://github.com/unpoller/unpoller.git
synced 2026-09-30 03:21:28 +02:00
Metrics/Events/Initialize each fan out to input plugins in their own goroutines with no recover(), so a panic there (e.g. a UniFi controller returning an unexpected Site Speed Test aggregated-dashboard payload) crashes the whole process with exit code 2. Because the panic occurs in a child goroutine, promunifi's existing safeRefresh recover() in the caller's goroutine never sees it, which is why the crash survived the earlier robustness work. This converts a panicking input into a logged/returned error so polling continues instead of crashing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
67 lines
1.6 KiB
Go
67 lines
1.6 KiB
Go
package poller_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/unpoller/unpoller/pkg/poller"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// panicInput is an Input that panics on Metrics and Events, simulating a
|
|
// malformed controller response crashing an input plugin. See issue #1030.
|
|
type panicInput struct{}
|
|
|
|
func (panicInput) Initialize(poller.Logger) error { return nil }
|
|
|
|
func (panicInput) Metrics(*poller.Filter) (*poller.Metrics, error) {
|
|
panic("simulated aggregated-dashboard panic")
|
|
}
|
|
|
|
func (panicInput) Events(*poller.Filter) (*poller.Events, error) {
|
|
panic("simulated aggregated-dashboard panic")
|
|
}
|
|
|
|
func (panicInput) RawMetrics(*poller.Filter) ([]byte, error) { return nil, nil }
|
|
|
|
func (panicInput) DebugInput() (bool, error) { return false, nil }
|
|
|
|
func TestCollectMetricsRecoversPanickingInput(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
collector := poller.NewTestCollector(t)
|
|
collector.AddInput(&poller.InputPlugin{Name: "panic-input", Input: panicInput{}})
|
|
|
|
var metrics *poller.Metrics
|
|
|
|
var err error
|
|
|
|
require.NotPanics(t, func() {
|
|
metrics, err = collector.Metrics(nil)
|
|
})
|
|
|
|
assert.NotNil(t, metrics)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "panic-input")
|
|
}
|
|
|
|
func TestCollectEventsRecoversPanickingInput(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
collector := poller.NewTestCollector(t)
|
|
collector.AddInput(&poller.InputPlugin{Name: "panic-input", Input: panicInput{}})
|
|
|
|
var events *poller.Events
|
|
|
|
var err error
|
|
|
|
require.NotPanics(t, func() {
|
|
events, err = collector.Events(nil)
|
|
})
|
|
|
|
assert.NotNil(t, events)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "panic-input")
|
|
}
|