feat(sources)!: split source contracts into PollSource/StreamSource and add mode-aware source config

- Introduce explicit source interfaces: sources.PollSource and sources.StreamSource, with shared sources.Input (Name() only).
- Remove mandatory Kind() from the base source contract to support sources that emit multiple kinds.
- Add config.SourceMode (poll, stream, or omitted/auto) and SourceConfig.Kinds (plural expected kinds), while keeping legacy SourceConfig.Kind for compatibility.
- Enforce mode semantics in config validation (poll requires every, stream forbids every) and detect mode/driver mismatches in sources.Registry.
- Update docs and tests for the new source model and config behavior.
This commit is contained in:
2026-03-15 19:19:19 -05:00
parent fafba0f01b
commit 6c5f95ad26
12 changed files with 591 additions and 542 deletions

56
config/config_test.go Normal file
View File

@@ -0,0 +1,56 @@
package config
import (
"reflect"
"testing"
)
func TestSourceConfigExpectedKinds(t *testing.T) {
tests := []struct {
name string
cfg SourceConfig
want []string
}{
{
name: "plural kinds preferred",
cfg: SourceConfig{
Kinds: []string{" observation ", "forecast"},
Kind: "alert",
},
want: []string{"observation", "forecast"},
},
{
name: "legacy singular fallback",
cfg: SourceConfig{
Kind: " alert ",
},
want: []string{"alert"},
},
{
name: "empty kinds",
cfg: SourceConfig{},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.cfg.ExpectedKinds()
if !reflect.DeepEqual(got, tt.want) {
t.Fatalf("ExpectedKinds() = %#v, want %#v", got, tt.want)
}
})
}
}
func TestSourceModeNormalize(t *testing.T) {
if got := SourceMode(" Poll ").Normalize(); got != SourceModePoll {
t.Fatalf("Normalize poll = %q, want %q", got, SourceModePoll)
}
if got := SourceMode("STREAM").Normalize(); got != SourceModeStream {
t.Fatalf("Normalize stream = %q, want %q", got, SourceModeStream)
}
if got := SourceMode("").Normalize(); got != SourceModeAuto {
t.Fatalf("Normalize auto = %q, want %q", got, SourceModeAuto)
}
}